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
*/