Codeforces 87C Interesting Game (sg博弈)

24 篇文章 0 订阅
23 篇文章 0 订阅

C. Interesting Game
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Two best friends Serozha and Gena play a game.

Initially there is one pile consisting of n stones on the table. During one move one pile should be taken and divided into an arbitrary number of piles consisting of a1 > a2 > ... > ak > 0 stones. The piles should meet the condition a1 - a2 = a2 - a3 = ... = ak - 1 - ak = 1. Naturally, the number of piles k should be no less than two.

The friends play in turns. The player who cannot make a move loses. Serozha makes the first move. Who will win if both players play in the optimal way?

Input

The single line contains a single integer n (1 ≤ n ≤ 105).

Output

If Serozha wins, print k, which represents the minimal number of piles into which he can split the initial one during the first move in order to win the game.

If Gena wins, print "-1" (without the quotes).

Examples
input
Copy
3
output
2
input
Copy
6
output
-1
input
Copy
100
output
8

【题目链接】
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;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值