[HDU-6883] Coin Game(2020HDU多校第十場T7)


[HDU-6883] Coin Game(2020HDU多校第十場T7)

題目給出的模型看起來比較奇怪,但是簡單推理后,發現可以轉化為一個簡單的01背包問題

對於題目給定的權值\(a_i,b_i\),分為\(a_i,a_i+b_i\)兩個物品,發現可以得到這個機器的所有合法貢獻情況

也就是說,有兩種大小分別為\(1,2\)的物品,要做01背包

這個剛剛在WC2020考過。。。

設兩類轉化后的權值分別為\(a_i,b_i\),則轉移過程可以簡單描述為

1.將兩類權值分別從大到小排序

2.將dp值轉化為在兩個序列中分別選取一段前綴和

3.轉移時枚舉下一次決策的選取是那種物品,選取最優一個,記錄指針轉移即可

主要復雜度可能還在於排序,Trick:有一點卡內存

但是實測桶排和直接sort好像差距不大。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)

const int N=5e6+10,INF=1e9;

int n,m;
int a[N],b[N];
ull k1,k2;
int Shift(){
    ull k3=k1,k4=k2;
    k1=k4;
    k3^=k3<<23;
    k2=k3^k4^(k3>>17)^(k4>>26);
    return (k2+k4)%10000000+1;
}
int A[N*3],B[N*3]; // 記錄在兩個序列中的指針
ll dp[3]; // dp數組滾動了一下

int main(){
    while(~scanf("%d%d%llu%llu",&n,&m,&k1,&k2)) {
        rep(i,1,n) a[i]=Shift(),b[i]=Shift()+a[i];
        sort(a+1,a+n+1,greater<int>()),sort(b+1,b+n+1,greater<int>());

        A[0]=B[0]=1;
        rep(i,0,2) dp[i]=0;
        ll ans=0;
        int cur=0;
        rep(i,0,m) {
            if(i+1<=m && A[i]<=n) {
                int nxt=(cur+1)%3;
                if(dp[cur]+a[A[i]]>dp[nxt]) dp[nxt]=dp[cur]+a[A[i]],A[i+1]=A[i]+1,B[i+1]=B[i];
            }
            if(i+2<=m && B[i]<=n) {
                int nxt=(cur+2)%3;
                if(dp[cur]+b[B[i]]>dp[nxt]) dp[nxt]=dp[cur]+b[B[i]],A[i+2]=A[i],B[i+2]=B[i]+1;
            }
            ans^=dp[cur];
            cur=(cur+1)%3;
        }
        printf("%lld\n",ans);
    }
}



免責聲明!

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



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