您的位置:首页 > 其它

BZOJ1874: [BeiJing2009 WinterCamp]取石子游戏

2016-03-16 09:50 288 查看
AC链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1874

首先开头点歌 Eason 《1874》。多么有意义的题目编号啊...

唔,这题感觉和经典的NIM取石子还是扯不开关系啊...

有了上一题的经验,我们知道了SG函数是可以递推求的,整个的状态是可以由一些小状态异或相加的。

然后怎么递推呢?当然就是根据后继状态来咯...

笔者此时还没有想起可以用时间戳这种方法来弄一个桶。

所以思考了一会儿桶要开多大:

  发现至多会有x个后继状态,那么桶中从0开始连续的一段就最多连续x下,所以只要开x+1这么大就可以了,不过>x要记得判掉。(可是如果所有人的x相同那就找到k使得2^(k-1)<=x<=2^k,那么最大的数也只能达到2^k)

  不过我这题还是开了1000,毕竟复杂度很充足...

好吧,时间戳就是常见的多次使用一个桶不用清空的那个神奇trick了,你们一定会的。

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=11;
const int maxz=1010;

int n,m;
int a[maxn],b[maxn];
int SG[maxz];
bool T[maxz];

int main(){
#ifndef ONLINE_JUDGE
freopen("1874.in","r",stdin);
freopen("1874.out","w",stdout);
#endif

int Max=0,ans=0;

scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(Max<a[i]) Max=a[i];
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
scanf("%d",&b[i]);

for(int i=1;i<=Max;i++){
memset(T,0,sizeof(T));
for(int j=1;j<=m;j++)
if(i>=b[j])
T[SG[i-b[j]]]=true;
for(int j=0;j<maxz;j++)
if(!T[j]) {SG[i]=j;break;}
}

for(int i=1;i<=n;i++) ans^=SG[a[i]];

if(!ans) {puts("NO");return 0;}

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
if(a[i]>=b[j])
if((ans^SG[a[i]-b[j]]^SG[a[i]])==0){
puts("YES");
printf("%d %d",i,b[j]);
return 0;
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: