题目大意:给出 n 个武器,每个武器可以升级最多 k[ i ] 次,每次升级需要花费 c[ i ][ j ] 个单位的金币,性能可以提升 w[ i ][ j ] 个单位,现在给出 m 个金币,问如何分配可以使得总性能最大
题目分析:n 只有 20,k 只有 4,直接搜索的话时间复杂度为 5^20,显然是不可行的,之前做过一个模型一样的题目:AcWing - 171,所以不难想到可以写双向dfs+二分,直接实现就好了
有一个坑点就是,在储存了数组 c 和 w 后,因为需要求前缀和,4 * 1e9 会爆掉 int,所以全部涉及到数值的地方都要开 long long
代码:
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> using namespace std; typedef long long LL; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const int N=1e6+100; int n,m,limit,num[N]; LL cost[N][5],val[N][5]; LL ans; vector<pair<LL,LL>>node;//(cost,val) void dfs1(int step,LL c,LL v)//搜1~limit { if(step>limit) { node.emplace_back(c,v); return; } for(int i=0;i<=num[step];i++)//0~num[step],0的意思是不选 if(c+cost[step][i]<=m) dfs1(step+1,c+cost[step][i],v+val[step][i]); } LL get_pos(int v)//小于等于v的最大值 { int l=0,r=node.size()-1; LL ans=0; while(l<=r) { int mid=l+r>>1; if(node[mid].first<=v) { l=mid+1; ans=node[mid].second; } else r=mid-1; } return ans; } void dfs2(int step,LL c,LL v)//搜limit+1~n { if(step>n) { ans=max(ans,v+get_pos(m-c)); return; } for(int i=0;i<=num[step];i++)//0~num[step],0的意思是不选 if(c+cost[step][i]<=m) dfs2(step+1,c+cost[step][i],v+val[step][i]); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.ans.txt","w",stdout); #endif // ios::sync_with_stdio(false); int w; cin>>w; int kase=0; while(w--) { node.clear(); ans=0; scanf("%d%d",&n,&m); limit=n/2; for(int i=1;i<=n;i++) { scanf("%d",num+i); for(int j=1;j<=num[i];j++) { scanf("%lld%lld",val[i]+j,cost[i]+j); cost[i][j]+=cost[i][j-1]; val[i][j]+=val[i][j-1]; } } dfs1(1,0,0); sort(node.begin(),node.end()); node.erase(unique(node.begin(),node.end()),node.end()); for(int i=1;i<node.size();i++) node[i].second=max(node[i].second,node[i-1].second); dfs2(limit+1,0,0); printf("Case #%d: %lld\n",++kase,ans); } return 0; }
