HDu 4317 Unfair Nim(デジタルDP,4級)

5331 ワード

Unfair Nim
Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 662    Accepted Submission(s): 271
Problem Description
Alice and Bob are tired of playing the Nim game, because they are so clever that before the beginning of the game, they have already known the result. Here is their conversation:
Bob: It's unfair. I am always the second player, but you know, if the number of stones in each pile are distributed uniformly, at most time the first player, i.e., you, will win.
Alice: Yes, I agree with you. So I give you a chance to beat me, you are allowed to add some stones in some piles (but you can't create a new pile) before the game starts, so that you can win as the second player.
Bob: Yeah, that's cool. I will win definitely.
Alice: But note, you must add the minimum of the stones. If you add more stones than necessary to win, your winning will be cancelled.
Bob: er... Let me see...
For the readers who are not familiar with the Nim game (from Wikipedia):
Nim is a mathematical game of strategy in which two players take turns removing stones from distinct heaps. On each turn, a player must remove at least one stone, and may remove any number of stones provided they all come from the same heap. The player who take the last stone wins.
 
Input
The first line of each test case contains an integer N (1 <= N <= 10), the number of piles at the beginning. The next line contains N positive integers, indicating the number of stones in each pile. The number of stones in each pile is no more than 1,000,000.
 
Output
Output one line for each test case, indicating the minimum number of stones to add. If it is impossible, just output "impossible".
 
Sample Input

   
   
   
   
3 1 2 3 3 1 1 1 1 10

 
Sample Output

   
   
   
   
0 3 impossible

 
Author
TJU
 
Source
2012 Multi-University Training Contest 2
 
Recommend
zhuyuanchen520
考え方:dp[x][y]は、右から左に数え、x位1が偶数の状態での進位状態yであり、その後、様々な条件を判断する.
私たちのDPは右から左へ行い、まず各列の状態を保存し、バイナリで表します. 7,5,0,0(右が低位であると仮定)
では、f[i][j]が右からi番目のビット保証列の1の個数が偶数であることを示す場合、キャリーの状態はj(キャリーの状態は上記の各列の状態と同様、各数がキャリーを生じる状態)とする
f[i][j]=min{f[i-1][k]+がキャリー後の列を満たす1の個数が偶数であり、キャリー状態が1に必要な数の和}
具体的な判断はビット演算で行い、
     tmp=s[i]&kはi列目に必ず生じるキャリーを表す  
     s[i]^kは、前のキャリーを加えた列の状態を表します 
     j^tmpは再進位が必要なのはどれですか
     s[ i ]^k  &   j^tmp ==    j^tmpは、必要なビットがすべて1であることを満たしてこそ、キャリーに成功する(0であれば、1を加算してもキャリーできない場合は、2を加算した場合は上位の計算に変換できる)
     s[ i ]^k  ^   j^tmpはキャリーを満たした状態を表し、この状態で1を満たさなければならない個数は偶数であり、奇数でnより少ない個数であれば、任意に0の位置に1を加えればよいが、答えは1回以上加えればよい.
fp_hzq
注意:すべて&などの操作を持って、すべて括弧をプラスしなければならなくて、(これで、1时间に调达して、ご饭はすべて食べていません...)
#include<iostream>
#include<cstring>
#include<cstdio>
#define gb(x) (1<<x)
using namespace std;
const int mm=1<<11;
int dp[25][mm],s[25],bit[mm],f[25];
int n;
int getbit(int x)
{
    int ret=0;
    while(x)
    {
        ret+=x&1;
        x>>=1;
    }
    return ret;
}
int main()
{
    for(int i=0; i<mm; ++i)
        bit[i]=getbit(i);
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; ++i)
            scanf("%d",&f[i]);
        if(n<2)
        {
            puts("impossible");
            continue;
        }
        int m;
        memset(s,0,sizeof(s));
        for(int i=1; i<25; ++i)
        {
            for(int j=0; j<n; ++j)
                if(f[j]&gb(i-1))
                    s[i]|=gb(j);
            if(s[i])m=i+1;
        }
        memset(dp,0x3f,sizeof(dp));
        int ans=dp[0][0];
        dp[0][0]=0;
        int tmp;
        for(int i=1; i<=m; ++i)
            for(int j=0; j<gb(n); ++j)
                if(dp[i-1][j]<ans)
                {
                    tmp=j&s[i];///      
                    for(int k=tmp; k<gb(n); ++k) ///k     
                    {
                        if(((k&tmp)==tmp)&&///      
                                ((s[i]^j)&(tmp^k))==(tmp^k)&&///       
                                ((bit[s[i]^j^tmp^k]&1)==0||bit[s[i]^j^tmp^k]<n)///      tmp^k
                          )
                        {
                            ///if(k==0)puts("www");
                            int z=bit[tmp^k]+(bit[s[i]^j^tmp^k]&1);
                            dp[i][k]=std::min(dp[i][k],dp[i-1][j]+(bit[tmp^k]+(bit[s[i]^j^tmp^k]&1))*gb(i-1));
                            ///cout<<dp[i][k]<<" i k "<<i<<" "<<k<<" "<<j<<" "<<z<<" "<<tmp<<endl;
                        }
                    }
                }
        for(int i=0; i<gb(n); ++i)
            if((bit[i]&1)==0)
            {
                ans=std::min(ans,dp[m][i]);
            }
        printf("%d
",ans); } }