看了解题报告才知道怎么做!!
题意:有 N 堆石子和 M 个石子回收站,每回合操作的人可以选择一堆石子,从中拿出一些 放到石子回收站里(可以放进多个回收站,每个回收站可以使用无数次),但每个石子回收站每次 只能接收特定数量的石子。不能操作的输。如果有人操作完之后,有任意一堆石子无法完全回收, 那么他直接输。
一个显然的结论是,每个游戏的 SG 值就是用 M 个回收站,完全回收这堆石子可行的最大 操作次数。由于最大的 Bi 比较小,立方暴力背包即可(比较显然的是,maxBi2 以上的周期是 minBi)。
而最大也就是10000,所以可以直接暴力求解sg值,找到最大操作次数。
ps:看到有人竟然仅仅用了50+B的代码就A了,真乃牛人啊,膜拜……
代码如下:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define I(x) scanf("%d",&x) 7 using namespace std; 8 int sg[10001],a[100001]; 9 char x[20],y[20]; 10 int main(){ 11 int n,m,i,j,MIN,b,t,ans; 12 while(scanf("%d%d%s%s",&n,&m,x,y)!=EOF){ 13 memset(sg,-1,sizeof(sg)); 14 sg[0]=0;MIN=1e9; 15 bool flag=0; 16 for(i=0;i<n;i++) I(a[i]); 17 for(i=0;i<m;i++){ 18 I(b); 19 MIN=min(MIN,b); 20 for(j=0;j+b<=10000;j++) 21 if(sg[j]>=0) 22 sg[j+b]=max(sg[b+j],sg[j]+1); 23 } 24 ans=0; 25 for(i=0;i<n;i++){ 26 t=a[i]; 27 if(t<=10000){ 28 if(sg[t]<0) flag=1; 29 else ans^=sg[t]; 30 } 31 else{ 32 t=(t-10000+MIN)%MIN+10000-MIN; 33 if(sg[t]<0) flag=1; 34 else ans^=sg[t]+(a[i]-t)/MIN; 35 } 36 } 37 if(!flag&&ans) puts(x); 38 else puts(y); 39 } 40 return 0; 41 }