HDU - 4388 Stone Game II

题目大意:n个石子堆,二人轮流取石子,每次可以从堆中取走k(1

思路:每次操作将一个堆分为k和k^x(先不考虑技能),直到无法再分。我们去看x和k、k^x有什么关系。

众所周知,异或是不进位的加法,我们去观察的话要从每一位去入手。如果此时x二进制上某一位为0,那么x和k^x此时对应位为0,0或者1,1;如果x某一位为1,那么x和k^x为1,0或者0,1,,拓展到整个x,k,k^x上,则有x中1的数量的奇偶与k与k^x中1的数量和奇偶一样。

接下来我们去找必败态,什么时候x无法再继续分解了呢。当x中只有一个1时,此时无法分解了(k拿走了若干1,则被拿走的位在k^x中也必为1,而最高位也为1,不满足k^x

最后我们看下技能,现在我们肯定从位运算的角度来思考了,发现就是将k左移一位,还是满足异或的加减法规律的——1数量奇偶性不变,所以用了这技能也无事发生。= =

由此得出结论1数量为奇必败,为偶则必胜,求一下有多少个必胜态即可,奇数个则必胜,偶数个则必败(抵消了)。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define scd(v) scanf("%d",&v)
#define scdd(a,b) scanf("%d %d",&a,&b)
#define endl "\n"
#define IOS ios::sync_with_stdio(false)
#define pb push_back
#define all(v) v.begin(),v.end()
//#define int long long
#define mst(v,a) memset(v,a,sizeof(v))
const int N = 1e6+10;
const int MAXN = 1e7+10;
int n,m;
int get(int x)//x中有多少个1,一个1为必败态
//x为一个堆,一个堆最多可以分为一个P和N,统计所有PN个数即可
//而必败态至少大于等于必胜态个数
{
    int cnt=0;
    while( x )
    {
        cnt += (x&1);
        x>>=1;
    }
    return cnt;
}
signed main()
{
    //!!
//    freopen("data.txt","r",stdin);
    //!!
//    IOS;
    int T;
    int TT=0;
    scd(T);
    while( T-- )
    {
        scd(n);
        int cnt=0;
        _for(i,1,n)
        {
            int x;scd(x);
            if( get(x)%2==0 ) cnt ^=1;//必败态个数
        }
        if( !cnt ) printf("Case %d: No\n",++TT);
        else printf("Case %d: Yes\n",++TT);
    }
}

 

你可能感兴趣的:(博弈)