HDU - 4388 Stone Game II
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 4388 Stone Game II相关的知识,希望对你有一定的参考价值。
题目大意:n个石子堆,二人轮流取石子,每次可以从堆中取走k(1<k<n且k^x<x)个石子,然后加入一个新堆k^x个石子,有一个技能可以加入(2k)^x个石子,不过一局只能用一次,问先手胜负
思路:每次操作将一个堆分为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<x)。如果1中数量大于1呢,从上面结论知道,1的奇偶性分解后不变,对于先手,如果此时1数量为偶,那肯定分为两个只含有一个1的数,此时为必胜态;如果此时1数量为奇,只能分为奇+偶 = 奇+必胜 = 必败态(奇数个最后转化成3个1情况)。
最后我们看下技能,现在我们肯定从位运算的角度来思考了,发现就是将k左移一位,还是满足异或的加减法规律的——1数量奇偶性不变,所以用了这技能也无事发生。= =
由此得出结论1数量为奇必败,为偶则必胜,求一下有多少个必胜态即可,奇数个则必胜,偶数个则必败(抵消了)。
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
#include <list>
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <deque>
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);
}
}
以上是关于HDU - 4388 Stone Game II的主要内容,如果未能解决你的问题,请参考以下文章