2020-2021 ICPC Northwestern European Regional Programming Contest (NWERC 2020) A.Atomic Energy (貪心,dp)


  • 題意:一個含有\(k\)個中子的原子,如果\(k\le n\),那么它就直接爆炸釋放\(a_k\)大小的能量,否則它會分裂成含有\(i\)個和\(j\)個中子的原子(\(i+j=k\)),然后繼續分裂.給你\(n\)\(a_1,a_2,...,a_n\),詢問\(q\)次,每次問你一個含有\(k\)個中子的原子分裂產生的最小能量.

  • 題解:這題當時我開的時候,有一個很明顯的貪心思路,就是可以先處理\(a\),找出對答案貢獻最小的\(a_i\),然后對於\(k>n\)的原子,我們一定優先分裂\(i\)個最優,但是分裂到一定值的時候就不能繼續這樣分裂了,舉個例子,假設\(n=4,k=8\),\(a_1=10000,a_2=1,a_3=4,a_4=10000\),那么首先將\(8\)分裂\(2\)\(6\),很顯然我們不能再將\(6\)分裂成\(2\)\(4\),而應分成\(3\)\(3\)最優.考慮到這,我想到可以類似完全背包來預處理前面一些狀況,然后對於很大的\(k\)可以分成兩段,一段用預處理的背包來給答案貢獻,另一段就是\(cnt*a_i\),但是這個預處理的常數給我卡死了,不知道為啥開小了會wa,如果有大佬知道請評論告訴孩子QAQ,另外,這題可以不找對答案貢獻最小的\(a_i\),\(n\)很小,完全可以枚舉.

  • 代碼:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 5e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n,q;
    ll a[N];
    ll dp[N];
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n>>q;
    	rep(i,1,n) cin>>a[i];
    	rep(i,1,5000000) dp[i]=5e18;
    	rep(i,1,n) dp[i]=a[i];
    	rep(j,n+1,5000000){
    		rep(i,1,n){
    			dp[j]=min(dp[j],dp[j-i]+dp[i]);
    		}
    	}
    	while(q--){
    		ll ans=5e18;
    		ll k;
    		cin>>k;
    		if(k<=1000000){
    			cout<<dp[k]<<'\n';
    			continue;
    		}
    		k-=1000000;
    		rep(i,1,n){
    			ll cnt=k/i;
    			ll rest=k%i;
    			ans=min(ans,cnt*a[i]+dp[1000000+rest]);
    		}
    		cout<<ans<<'\n';
    	}
     
        return 0;
    }
    


免責聲明!

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



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