P5365 英雄联盟(STL 灵活应用,VAI)
注:\(n\le 122\)。
这道题大抵是要用“STL灵活应用”了。
想到一种看着很对的设计:设 \(f(i)\) 表示还需要一个至少为 \(i\) 的数字代价。
真对吗?
有没有可能,\([[a/b]/c]<[a/(bc)]\)?
证明:
令 \(a=mb+n(n<b)\),则左侧等于 \([m/c]\),右侧等于 \([(mb+n)/(bc)]=[(m+n/b)/c]\)。
显然有 \(n/b<1\) 于是得证。
那么转移应当不难,\(i\) 的衰减非常快,应该能过。
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N=123;
map<ll,int> mp,tmp;
int n,k[N],w[N]; ll V;
signed main(){
scanf("%d%lld",&n,&V),mp[V]=0;
for(int i=1;i<=n;i++) scanf("%d",&k[i]);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1,lst;i<=n;i++){
tmp.clear();
for(auto it:mp) for(int j=2;j<=k[i];j++)
if(tmp.count((it.first+j-1)/j))
tmp[(it.first+j-1)/j]=min(tmp[(it.first+j-1)/j],it.second+j*w[i]);
else
tmp[(it.first+j-1)/j]=it.second+j*w[i];
for(auto it:tmp)
if(mp.count(it.first))
mp[it.first]=min(mp[it.first],it.second);
else
mp[it.first]=it.second;
}
printf("%d\n",mp[1]);
return 0;
}
但这个思路太唐了!
会发现这个无效状态特别多。
那这种时候怎么办呢?Welcome to VAI!
设 \(f(i)\) 表示用 \(i\) 的代价最多能达到权值。
最大值设一个 \(\sum v\) 之类就行。
时间复杂度 \(O((\sum w_i)(\sum k_i))=O(n^2wk)\) 可以通过本题。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=250000;
int n,k[N],w[N],sum; ll goal,f[N];
int main(){
scanf("%d%lld",&n,&goal);
for(int i=1;i<=n;i++) scanf("%d",&k[i]);
for(int i=1;i<=n;i++) scanf("%d",&w[i]),sum+=w[i]*k[i];
for(int i=0;i<=sum;i++) f[i]=1;
for(int i=1;i<=n;i++) for(int j=sum;j>=2*w[i];j--) for(int num=2;num<=k[i]&&num*w[i]<=j;num++)
f[j]=max(f[j],min(f[j-w[i]*num]*num,goal));
for(int i=1;i<=sum;i++) if(f[i]>=goal) printf("%d\n",i),exit(0);
return 0;
}

浙公网安备 33010602011771号