hdu4317 nim+状压dp, Unfair Nim 状态很容易想到,转移就恶心了。。。 不过屡清思路就好了
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <cstdlib> #include <cmath> #include <stack> #include <map> #include <vector> #include <string> #include <algorithm> const double pi=cos(-1.); const double eps=10e-6; const double eps1=10e-10; const int inf=0x5fffffff; const long long infl=1ll<<62; ///******macro defination******/// #define cas(a) int a; scanf("%d", &a); while (a--) #define cas1(x, a) int a; scanf("%d", &a); for (int x=1; x<=a; ++x) #define int(a) int a; scanf("%d", &a) #define char(a) char a; scanf("%c", &a) #define strr(a, x) char a[x]; scanf("%s", &a) #define clean(a) memset (a, 0, sizeof(a)); #define up(x,a) for(int x=0; x<a; ++x) #define down(x,a) for(int x=a-1; x>=0; --x) #define up1(x,a) for (int x=1; x<=a; ++x) #define debug(a) printf("here is %d!!!\n", a); ///*** mathmatics ***/// #define sqr(x) (x)*(x) #define abs(x) (x)>0?(x):(-(x)) #define zero(x) (x)<eps && (x)>eps ///****** by Geners ******/// typedef long long ll; typedef unsigned int UI; using namespace std; int nim[50]; int row[50]; /// 记录每位各个数的状态 int dp[50][1024+123];/// dp[i][j] i位为j进位时的最小值 /// dp[i][j]= min(dp[i-1][???] +bit(j)*(1<<i) , ) j&(~row) == 0 /// 如果当前位是0, 想进位 前状态必须也有进位, 即1+10+1=100 /// 不进位 前状态0 或1 /// 当前位是1, 进位 前状态 0、1 /// 不进位 前状态0 转移O(2^10 )总 O(20*2^20) int getbit(int x) { int res=0; while (x) { if(x&1)res++; x>>=1; } return res; } int main() { int n; while (~scanf("%d", &n)) { clean(row); int xsum=0; for (int i=0; i<n; ++i) scanf("%d", nim+i),xsum^=nim[i]; for (int i=0; i<23; ++i) { for (int j=0; j<n; ++j) { if(nim[j]&(1<<i))row[i]|=(1<<j); } //if(row[i])printf("row[%d]=%d\n", i, row[i]); } int maxb=20; for (int j=25; j>=0; --j) { if(row[j]==0)continue; maxb=j+1; break; } //printf("xorsum=%d maxb=%d\n", xsum, maxb); int lim=1<<n; int mask=lim-1; for (int i=0; i<=maxb; ++i) { for (int j=0; j<lim; ++j)dp[i][j]=inf; } for (int i=0; i<=maxb; ++i) { for (int j=0; j<lim; ++j) { int bi=getbit(j); if(i==0) { if((j&(~row[i]))==0) if((bi+(xsum&(1<<i))&1)==0) { dp[i][j]=bi; //printf("j==%d bi==%d %d\n", j, bi, row[i]); } else if((row[i]&mask)!=mask)dp[i][j]=bi+1; } else { for (int k=0; k<lim; ++k) { if(dp[i-1][k]>=inf)continue; //if(k==8 && i==1)printf(" %d %d\n", k|row[i], k & row[i]); if( ( j & ( ~( k|row[i] ) ) )==0 && (~j & ( k & row[i] ))==0 ) { if( ( ( bi - getbit(k^row[i]) - getbit(k&row[i]) ) & 1 ) ) { if((mask&(k^row[i]))!=mask) dp[i][j]=min(dp[i][j], dp[i-1][k]+(1<<i)*(bi-getbit(k&row[i])+1)); } else dp[i][j]=min(dp[i][j], dp[i-1][k]+(1<<i)*(bi-getbit(k&row[i]))); //printf("i==%d j==%d bi==%d k=%d %d dp=%d\n", i, j, bi, k, row[i], dp[i-1][k]+(1<<i)*(bi-getbit(k&row[i]))); } } } } } // for (int i=0; i<=maxb; ++i) // { // for (int j=0; j<lim; ++j) // { // if(dp[i][j]<inf)printf("(%d, %d)=%d\n", i, j, dp[i][j]); // } // } int ans=inf; for (int i=0; i<lim; ++i) { if(~getbit(i)&1) ans=min(ans, dp[maxb][i]); } if(ans==inf)puts("impossible"); else printf("%d\n", ans); } return 0; } /* 3 1 2 3 3 1 1 1 1 10 3 7 2 9 3 3 2 5 3 0 0 0 4 0 0 0 0 4 1 1 1 1 2 1000000 999999 5 35 9 7 48 28 4 1000000 999999 555 444 */