http://codeforces.com/problemset/problem/87/C
【题意】一开始有一堆数量为n的石子,每次把其中的一堆石子分成任意堆,要求分成的堆数满足a[1]-a[2]=a[2]-a[3]=a[3]-a[4]......=a[k-1]-a[k]=1,其中k>=2,如果先手能赢,输出先手第一次分石子应分的最小堆数,否则输出-1.
【思路】sg函数打表,求出其子状态的sg值。首先从3....n枚举石子数,内层再枚举当前可能分的堆数;假设当前分了m堆,这m堆中石子数量最少的为x个,又知当前m堆石子为等差数列,最小项为x,则可得当前m堆的石子总数量为(x-1)*m+(m*(m+1)/2);所以用当前总共的石子数量i-m*(m+1)/2的结果一定为m的倍数。然后通过其子状态的sg值异或得到当前状态的sg值即可。
【代码如下】
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,sg[N],mex[N];
int main(){
scanf("%d",&n);
int ans = -1;
int cnt = 1;
for(int i = 3; i <= n; i ++){
for(int m = 2; ; m ++){
int r = i - m*(m+1)/2;
if(r < 0) break;
if(r % m) continue;
int g = 0; //g表示其子状态的异或和
for(int j = 1; j <= m; j ++) g ^= sg[r/m+j];
if(!g && i==n && ans < 0) ans = m;
mex[g] = cnt;
}
for(int j = 0; ; j ++){
if(mex[j] != cnt){
sg[i] = j; cnt ++; break;
}
}
}
printf("%d\n",ans);
return 0;
}