SG函数与组合博弈问题

把组合博弈问题抽象成一个有向无环图,有n个棋子在上面移动,当AB两方其中一方移动不了时另一方获胜.
定义mex运算为集合内没有出现过的最小的自然数,则SG(x)=mex{SG(y)(其中y为x所扩展出的状态)}
结论:当有K组的博弈时若SG(n1)^SG(n2)^..SG(nK)!=0时先手获胜,否则后手获胜.
CF上的一道题:

A. The game of Osho
time limit per test2 seconds
memory limit per test64 megabytes
inputpowers.in
outputstandard output
Faheem and Faheema love to play what they call the game of Osho, in this game they choose a number N randomly, the first player subtracts a non-zero number Bk1 less than or equal to N from N, then the second player subtracts number Bk2 (where B is given and ki is a non negative integer number), then again the first and so on until one of the players loses when he/she can’t make any move. In other words, when it’s a player’s turn and N equals 0. For example let’s see this game when B=2 and N=3. The first player Faheem can subtract 1 or 2 the optimal move here is 1, N now equals 2. In her turn Faheema subtract 2 because 1 will make Faheem win, Faheem now can’t play any move and he loses.

After a while they found that this game is boring so they decided to upgrade it, their version combines multiple subgames of the form (Bi, Ni) and the player can choose which of them he wants to play his move in, a player loses when he/she can’t make a move.

Given the subgames, your job is to determine which player wins the whole game assuming that both players play optimally.

Input
The first line contains T, the number of test cases. The next T lines contain G (1 ≤ G ≤ 100) the number of subgames and then follows G pairs of integers (1 ≤ Bi, Ni ≤ 1, 000, 000, 000) describing each subgame.

Output
For each test case print 1 if the first player wins the game, or 2 if the second wins.

Examples
input
3
1 2 3
1 7 3
2 6 11 3 2
output
2
1
2
我是先打表找规律..

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;

#define ll long long
#define me(x) memset(x,0,sizeof(x))

ll f[105];
ll sg[500];
ll hashs[500];
ll fast(int a,int b)
{
  if (!b) return 1;
  if (b&1) return a*fast(a,b-1);
  ll t=fast(a,b/2); return t*t;
}
void  getsg(int b)
{

  int pos;
  for (int i=0;i<100;i++)
  {
    ll t=fast(b,i);
    if (t>1000000000) {pos=i-1;break;}
    f[i]=t;
    pos=i;
  }
  sg[0]=0;
  for (int i=1;i<=105;i++)
  {
    memset(hashs,0,sizeof(hashs));
    for (int j=0;f[j]<=i&&j<pos;j++)
    {
        hashs[sg[i-f[j]]]=1;
    }
    for (int j=0;;j++)
    {
      if (!hashs[j]) {sg[i]=j; break;}
    }
  }

}
int main()
{
  freopen("powers.in","r",stdin);
  int T;
  scanf("%d",&T);
  while (T--){
    //memset(sg,0,sizeof(sg));
    int n;
    scanf("%d",&n);
    int sum=0;
    for (int i=1;i<=n;i++)
    {
      int b,N;
      scanf("%d%d",&b,&N);
      //getsg(b);
      if (b&1) {if (N&1)sum=sum^1;else sum=sum^0;}
      else {
        if (N%(b+1)==b)sum=sum^2;
        else if (N%(b+1)&1) sum=sum^1;
             else sum=sum^0;
        }
    }
    if (!sum) printf("2\n");
    else printf("1\n");
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值