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;
}
posted @ 2026-02-13 22:38  2025ing  阅读(0)  评论(0)    收藏  举报