SRM709 div1 Xscoregame(狀壓dp)
阿新 • • 發佈:2017-06-21
壓縮 out find 初始 reg max algo pan 是我
題目大意:
給定一個序列a,包含n個數(n<=15),每個數的大小小於等於50
初始時x = 0,讓你每次選a中的一個數y,使得x = x + x^y
問如何安排選擇的次序,使得最終結果最大。
考慮狀態壓縮,dp[S]表示選了S狀態的數的最大結果
我們發現這樣做是錯誤的,因為目前的最大並不意味最後的最大
但是我們會發現,y最大只有50,所以x的大於63的部分不會發生變化,只有小於64的部分會受到y異或的結果
所以我們用dp[S][t]表示:選了S狀態的數,小於64部分為t是否可行
然後用dp[S][64]代表大於64部分的大小
選第i個數加入的轉移就是,先求出小於64部分與A[i]異或的最大值Max
然後大於64部分的大小就是2*dp[S][64] + (Max>>6)
找到所有小於64部分的異或>>6大於1的值,然後更新那些可行的狀態即可
最後輸出就是大於64的部分<<6再加上小於64部分最大的可行解
#include <cstdio> #include <cmath> #include <cstring> #include <ctime> #include <iostream> #include <algorithm> #include <set> #include<vector> #include <sstream> #include <typeinfo> #include <fstream> #include <queue> using namespace std; void print(int x){ cout<<"*"; while(x){ if(x&1) cout<<1; else cout<<0; x>>=1; } cout<<endl; }long long dp[(1<<15) + 1][100]; queue<int> Q; int vis[(1<<15) + 1]; void Find(int S){ for(int i = 0; i < 64; i++) if(dp[S][i]) cout<<i<<" "; cout<<dp[S][64]; cout<<endl; } class Xscoregame { public: int getscore(vector<int> A) { int n = A.size(); Q.push(0); dp[0][0] = 1; while(!Q.empty()){ int S = Q.front(); Q.pop(); //print(S); //Find(S); for(int i = 0; i < n; i++){ if(S&(1<<i)) continue; int Max = 0; for(int j = 0; j < 64; j++){ if(!dp[S][j]) continue; Max = max(Max, j + (j^A[i])); } if(Max == 0) continue; if(dp[S|(1<<i)][64] > 2*dp[S][64] + (Max>>6)) continue; if(dp[S|(1<<i)][64] != 2*dp[S][64] + (Max>>6)) for(int j = 0; j < 64; j++) dp[S|(1<<i)][j] = 0; if(!vis[S|(1<<i)]) Q.push(S|(1<<i)); vis[S|(1<<i)] = 1; dp[S|(1<<i)][64] = 2*dp[S][64] + (Max>>6); for(int j = 0; j < 64; j++){ if(!dp[S][j]) continue; int temp = j + (j^A[i]); if((temp>>6) == (Max>>6)) dp[S|(1<<i)][temp&63] = 1; } } } long long ans = 0, temp = 0; for(int i = 63; i >= 0; i--) if(dp[(1<<n)-1][i]) { temp = i; break; } ans += (dp[(1<<n)-1][64]<<6) + temp; return ans; } };
SRM709 div1 Xscoregame(狀壓dp)