[bzoj4600][SDOI2016]硬币游戏

4600: [Sdoi2016]硬币游戏

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 7 Solved: 5
[Submit][Status][Discuss]

首先我们可以发现,每个数的形式都是这样的: c2a3b
如果我们建立一个二维的坐标系,横坐标表示 a ,纵坐标表示b,可以这样表示的原因是因为这个游戏的规则。每次翻的点都是 c 相同的。所以就与c没什么关系了。
这样我们令 sg[i][j] 表示 i 这个点与之前所有点的状态不一样,翻这个点的sg值是多少。这个在求的时候可以暴力枚举所有的后继状态。
有一个问题就是在一个后继状态中会被翻的所有的点得 sg 值怎么表示?在计算答案的过程中翻一个点会不会对前面的点有影响?
其实这两个是一个问题,就是这个点和它的后继点是否是独立的。
其实是独立的。我们可以看求 sg 的过程,假如我们翻了这个点后会对前面有些点产生影响,但是对于某一个点来说被翻得总次数是一定的,只是先后顺序不同,所以无论顺序是怎样这个点的状态都会是这个,也就是说这个点可以看成是独立的。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool flag[500];
int T,n,maxq,SG[20][20];
inline void solve2(){
    int i,j,p,q,k,x=0,y=0,o;
    o=n;while(o>=2) ++x,o/=2;
    o=n;while(o>=3) ++y,o/=3;
    memset(SG,0,sizeof(SG));
    for(i=0;i<=x;++i)
      for(j=0;j<=y;++j){
        memset(flag,0,sizeof(flag));
        for(p=1;p<=i;++p)
          for(q=1;q<=maxq&&p*q<=i;++q){
            for(o=-1,k=1;k<=q;++k) o=(o==-1)?SG[i-p*k][j]:(o^SG[i-p*k][j]);
            if(o!=-1) flag[o]=true;
          }
        for(p=1;p<=j;++p)
          for(q=1;q<=maxq&&p*q<=j;++q){
            for(o=-1,k=1;k<=q;++k) o=(o==-1)?SG[i][j-p*k]:(o^SG[i][j-p*k]);
            if(o!=-1) flag[o]=true;
          }
        for(o=0;;++o)
          if(!flag[o]){
            SG[i][j]=o;
            break;
          }
      }
}
int main(){
    int i;
    scanf("%d",&T);
    while(T--){
        int now=0,o;
        scanf("%d%d",&n,&maxq);
        solve2();
        for(i=1;i<=n;++i){
            scanf("%d",&o);
            if(o) continue;
            int o2=0,o3=0;
            o=i;while(o%2==0) ++o2,o/=2;
            while(o%3==0) ++o3,o/=3;
            now^=SG[o2][o3];
        }
        if(now) printf("win\n");
        else printf("lose\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值