您的位置:首页 > 其它

bzoj4600 [Sdoi2016]硬币游戏 sg函数+结论

2018-03-07 10:50 411 查看
sg[maxQ][二的次数][三的次数]=前面的都是正面的胜负状态
C不一样的相互独立
首先顺序是不重要的,因为他有一个模仿关系。
比如   9,3是0    必胜策略是 选9翻9 、3
  由于是异或,所以必胜策略可以理解为 选9 翻 9  ,这样3的位置就需要翻两遍,也就相当于翻0次
就可以理解为3这位置状态已经是0(实际操作相当于可以模仿掉)
所以如果存在必胜策略,一定可以拆为每个点sg值的若干组合。选取一个0点把 前面的0点变成1的操作
可以在独立的点角度 理解为保留前面的0点,剩下的用 前面0点的sg来异或等于0,
因为若先手为0,后手一定可以为1 先手为1,后手一定为0,就相当于不能翻
也可以用异或的性质理解。。
码:#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int sg[23][55][55],n,T,i,j,Q,ans,o,er[30005],san[30005];
int SG(int Q,int a,int b)
{
if(sg[Q][a][b]!=-1)return sg[Q][a][b];
int i,j,q,p;
bool v[101];
memset(v,0,sizeof(v));
for(p=1;p<=a;p++)
{int lin=0;
for(q=1;q<=Q;q++)
{
if(p*q>a)break;
lin^=SG(Q,a-p*q,b);
v[lin]=1;
}
}
for(p=1;p<=b;p++)
{int lin=0;
for(q=1;q<=Q;q++)
{
if(p*q>b)break;
lin^=SG(Q,a,b-p*q);
v[lin]=1;
}
}
for(i=0;i<=100;i++)
{
if(v[i]==0)
{sg[Q][a][b]=i;break;}
}
return sg[Q][a][b];
}
int main()
{
scanf("%d",&T);
memset(sg,-1,sizeof(sg));
for(Q=1;Q<=20;Q++)
for(i=0;i<=15;i++)
for(j=0;j<=15;j++)
{
SG(Q,i,j);
}
int linn=0;
for(i=1;i<=30000;i++)
{
o=i;
int o2=0;
int o3=0;
while(o%2==0)
o/=2,o2++;
while(o%3==0)
o/=3,o3++;
er[i]=o2;san[i]=o3;
linn=max(linn,max(o2,o3));
}
while(T--)
{ans=0;
scanf("%d%d",&n,&Q);
for(i=1;i<=n;i++)
{
scanf("%d",&o);
if(o==1)continue;
ans^=sg[Q][er[i]][san[i]];
}
if(ans==0)printf("lose\n");
else printf("win\n");
}
}
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: