NWERC 2020A Atomic Energy(背包+思維)


對於這題,觀察到數據范圍,首先觀察出第一個性質

最后只需要找到兩個和大於n的,減去這兩個值后,k就可以通過任意選擇組合而來。

如果k的數據范圍很小,那么我們可以直接背包求取答案。

現在k有1e9,那就需要其他的性質。

又因為我們觀察到數是連續的,因此假如當時我們有一個效率最高的數,也就是a[i]/i最小的那個。

那么最后的正解里面,一定有大部分數和可以成為這個i的倍數,這樣就可以用這個i來替換掉,從而縮減范圍。

由於數是連續的,根據鴿巢原理,最后剩下不能組成i的倍數的數不超過m+1個。我們預處理前面的背包。

所以我們只需要找到一個比這個上界大的數,那么k就是由j*am+f[k-j*am]更新而來。

這一步是因為由於在正解中和不為選中i的數最多m+1個,因此用他們組成的結果不會大於(m+1)*n,所以大於他的數都需要am來更新。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=1e6+10;
const int mod=998244353;
ll f[N];
ll a[N];
ll ff[N];
int m;
int main(){
    ios::sync_with_stdio(false);
    int i,j;
    int n,q;
    cin>>n>>q;
    for(i=1;i<=n;i++){
        cin>>a[i];
        if(!m||1.0*a[i]/i<1.0*a[m]/m){
            m=i;
        }
    }
    for(i=0;i<N;i++){
        f[i]=1e12;
        ff[i]=1e12;
    }
    f[0]=0;
    for(i=1;i<=n;i++){
        for(j=i;j<=2e4;j++){
            f[j]=min(f[j],f[j-i]+a[i]);
        }
    }
    for(i=1;i<=n;i++){
        for(j=n-i+1;j<=n;j++){
            ff[i+j]=min(ff[i+j],a[i]+a[j]);
        }
    }
    while(q--){
        ll k;
        cin>>k;
        ll ans=1e18;
        if(k<=n){
            cout<<a[k]<<endl;
            continue;
        }
        for(i=n+1;i<=2*n;i++){
            if(i>k)
                continue;
            ll g=k-i;
            ll tmp=ff[i];
            if(g<=2e4){
                ans=min(ans,tmp+f[g]);
                continue;
            }
            ll d=g-2e4;
            d=d/m+1;
            int sign=0;
            tmp+=(d*a[m])+f[g-d*m];
            ans=min(ans,tmp);
        }
        cout<<ans<<endl;
    }
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM