Good Luck in CET-4 Everybody! HDU - 1847

题意:一堆n个的牌,每次抽1,2,4,8(2^k)张,最后不能取的输

思路:

直接手写博弈树,发现3的倍数一定为必败态.大胆猜想必败态,借着接着从3个性质证明

1. 当n=0(终止状态) 必败

2.对于当前局面是必败的,任何操作都只能转移到必胜态

3.对于当前局面必胜,可以转移到必败态

证明:

1.显然成立

2.   即  因为 2^k不可能有因数3,因此一定不能整除,所以对于当前为必败态的局面,任何操作都只能转为必胜态

3. 对于一个数n , 我们要证明,在n%3!=0的情况下, 一定存在一个k,  使得 . 打表表明在n <= 1000 的情况下一定成立.    等价    n%3=0,1,2    2^k%3=0,1,2  证毕

看了下网上说的是Bash博弈,想想有道理. 但是大多数博客对结论没证明

对于递归和非递归的版本,  sg上限是 1000

#include<cstdio>
#include<vector>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1005;
const int MOD=1e9+7;
const double EPS=1e-10;
template <class T>
bool sf(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}

int main(void){
    int n;
    while(scanf("%d",&n)==1){
        if(n%3==0)  printf("Cici\n");
        else    printf("Kiki\n");
    }
}

作为第一题博弈题,再写一遍get_sg和dfs版本

//SG函数版本
#include<cstdio>
#include<vector>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=10005;
const int MOD=1e9+7;
const double EPS=1e-10;
template <class T>
bool sf(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
int sg[N];
bool vis[N];
int f[N];
void get_sg(){
    int t=1;
    for(int i=1;i<=20;i++){
        f[i]=t;
        t*=2;
    }
    memset(sg,0,sizeof sg);
    sg[0]=0;
    for(int n=1;n<=1000;n++){
        memset(vis,0,sizeof vis);
        for(int j=1;j<=20&&n>=f[j];j++) vis[sg[n-f[j]]]=1;
        for(int i=0;i<=1000;i++){
            if(!vis[i]){
                sg[n]=i;
                break;
            }
        }
    }
    return ;
}
int main(void){
    get_sg();
    int n;
    while(scanf("%d",&n)==1){
        if(sg[n])   printf("Kiki\n");
        else    printf("Cici\n");
    }

    return 0;
}
//sg_dfs版
#include<cstdio>
#include<vector>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=10005;
const int MOD=1e9+7;
const double EPS=1e-10;
template <class T>
bool sf(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
int sg[N];
int f[N];
int sg_dfs(int n){
    if(sg[n]!=-1)   return sg[n];
    bool vis[50];
    memset(vis,false,sizeof vis);
    for(int i=1;i<=30&&f[i]<=n;i++){
        sg_dfs(n-f[i]);
        vis[sg[n-f[i]]]=1;
    }
    for(int i=0;i<=1000;++i){
        if(!vis[i]){
            return sg[n]=i;
        }
    }
}
int main(void){
    memset(sg,-1,sizeof sg);
    int t=1;
    for(int i=1;i<=20;i++)  f[i]=t,t*=2;
    sg_dfs(1000);
    int n;
    while(scanf("%d",&n)==1){
        if(sg[n])   printf("Kiki\n");
        else    printf("Cici\n");
    }

    return 0;
}