博弈论大作战之 PART1

来源:互联网 发布:java复制图片 编辑:程序博客网 时间:2024/04/27 14:14

HDU 1047

dp一下

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 40010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int mon[]={31,28,31,30,31,30,31,31,30,31,30,31};int run(int y){    if(y%4==0&&y%100!=0 || y%400==0) return 1;    return 0;}int f(int y,int m,int d){    int ans=d;    for(int i=1;i<m;i++) if(i==2) {        ans += mon[i-1];        if(run(y)) ans++;    }else {        ans += mon[i-1];    }    for(int i=1900;i<y;i++) if(run(i)) ans += 366;    else ans += 365;    return ans;}int win[nMax];void init(){    int n=f(2001,11,4);    win[n]=0;    for(int i=n-1;i>=1;i--){        int y,m,d,j=i;        y=1900;        while(1){            if(run(y)) if(j-366>0) j-=366,y++; else break;            else       if(j-365>0) j-=365,y++; else break;        }        m=1;        while(1){            if(m==2) {                if(run(y)) if(j-29>0) j-=29,m++;else break;                else       if(j-28>0) j-=28,m++;else break;            }else {                if(j-mon[m-1]>0) j-=mon[m-1],m++;else break;            }        }        d=j;        //if(i==n-1)        //printf("year=%d month=%d day=%d\n",y,m,d);        win[i]=0;if(win[i+1]==0) win[i]=1;        m+=1;        if(m==13) y++,m=1;        if(m==2) {            if(run(y)) { if(d>29) continue;}            else       if(d>28) continue;        }else {            if(d>mon[m-1]) continue;        }        //printf("--year=%d month=%d day=%d\n",y,m,d);        j=f(y,m,d);        if(j>n) continue;        if(win[j]==0) win[i]=1;    }}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    init();    int y,m,d,t;    scanf("%d",&t);    while(t--) {        scanf("%d%d%d",&y,&m,&d);        int i=f(y,m,d);        if(win[i]) puts("YES");        else       puts("NO");    }    return 0;}


HDU Play a game  

暴力一下发现n是偶数的时候必败,奇数的时候必胜。具体的原因有待研究。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int dx[]={-1,0,0,1};int dy[]={0,1,-1,0};int n;int in(int x,int y){    if(x<0 || x>=n)return 0;    if(y<0 || y>=n) return 0;    return 1;}int dfs(int a[nMax][nMax],int x,int y){    int ans=0;    for(int i=0;i<4;i++){        int u=x+dx[i],v=y+dy[i];        if(in(u,v)) {            if(!a[u][v]) {                a[u][v]=1;                if(dfs(a,u,v)==0) {                    ans = 1;                }                a[u][v]=0;            }        }        if(ans==1) return ans;    }    return ans;}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    /*int a[nMax][nMax];    for(n=1;n<10;n++) {        CLR(a);        a[0][0]=1;        printf("%d ",n);        if(dfs(a,0,0)) puts("1");        else puts("0");    }*/    while(cin>>n,n) {        if(n&1) printf("ailyanlu\n");        else printf("8600\n");    }    return 0;}

HDU1846 Brave Game  

最原始的巴什博奕(Bash Game)。当n是m+1的倍数的时候为必败态。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,m,t;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        if(n%(m+1)==0) printf("second\n");        else printf("first\n");    }    return 0;}

HDU1847 Good Luck in CET-4 Everybody!  

 dp一下就知道每个n是否是必胜的了。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int win[nMax];void init(){    win[0]=0;    for(int i=1;i<=1000;i++) {        win[i]=0;        for(int j=0;;j++){            if(i<(1<<j)) break;            if(win[i-(1<<j)]==0) {win[i]=1;break;}        }    }}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    init();    int n;    while(cin>>n){        if(win[n]) puts("Kiki");        else puts("Cici");    }    return 0;}


HDU2147 kiki's game 

 n或者m有一个为偶数的时候是必胜态,拿个笔画画就出来了。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 2010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int n,m;    while(scanf("%d%d",&n,&m),n||m){        if(n%2==0 || m%2==0) printf("Wonderful!\n");        else printf("What a pity!\n");    }    return 0;}

HDU2516 取石子游戏  

神奇的斐波那契。。只会找规律的飘过。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 1001#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>LL l[nMax];int k;void init(){    LL a=2LL,b=3LL;    k=0;    l[k++]=a,l[k++]=b;    while(b<oo){        LL c=a+b;        a=b;b=c;        l[k++]=b;    }    //cout<<k<<endl;}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    init();    LL n;    while(cin>>n,n){        int ok=1;        for(int i=0;i<k;i++) if(n==l[i]) ok=0;        printf("%s",ok?"First win\n":"Second win\n");    }}

HDU2897 邂逅明下   

算是巴什博奕(Bash Game)的变形吧。n对p+q的余数在[1,p]之间就是必败态。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,p,q;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    while(~scanf("%d%d%d",&n,&p,&q)){        n%=(p+q);        int ok;        if(n>=1 && n<=p) ok=0;        else ok=1;        printf("%s\n",ok?"WIN":"LOST");    }    return 0;}

HDU3032 Nim or not Nim? 

我们发现 sg[a] = a+1(a%4==3) , a-1(a%4==0) ,a(else);然后利用sg性质直接亦或就是答案了。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 1001#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int a,n,vis[nMax],sg[nMax];void init(){    sg[0]=0;    for(int i=1;i<101;i++) {        CLR(vis);        for(int j=1;j<=i;j++) {            vis[sg[i-j]]=1;            if(i-j>=0) vis[sg[j]^sg[i-j]]=1;        }        for(int j=0;j<1001;j++) if(!vis[j]) {sg[i]=j;break;}        printf("i=%d sg=%d\n",i,sg[i]);    }}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    //init();    int t;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        int ans=0;        while(n--) {            scanf("%d",&a);            if(a%4==3) ans ^= (a+1);            else if(a%4==0) ans ^= (a-1);            else ans ^= a;        }        printf("%s\n",ans==0?"Bob":"Alice");    }    return 0;}

HDU3537 Daizhenyang's Coin 

经典的翻硬币游戏,推荐参考大牛博客大牛博客IS HERE

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,a[nMax],ans;int f(int x){    int sum=0,y=x;    x*=2;    while(y){        if(y&1) sum++;        y>>=1;    }    if(sum&1) ;else x++;    return x;}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    while(~scanf("%d",&n)){        ans=0;        for(int i=0;i<n;i++) scanf("%d",&a[i]);        sort(a,a+n);        if(n)ans ^= f(a[0]);        for(int i=1;i<n;i++) if(a[i]!=a[i-1]) ans ^= f(a[i]);        printf("%s\n",ans?"No":"Yes");    }    return 0;}

HDU3951 Coin Game  

我们研究一条链的情况,当k=1时,n为偶数必败。当k>1时,n为任何数必胜,因为我们可以将这条链拆成两条长度相同的链,那么无论对方做什么操作,我们就做相同的操作,最后肯定必胜。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,k,t;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int cas=1;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&k);        printf("Case %d: ",cas++);        if(k==1) {            printf("%s\n",n%2?"first":"second");        }else {            printf("%s\n",n<=k?"first":"second");        }    }    return 0;}

HDU2188 悼念512汶川大地震遇难同胞——选拔志愿者  

巴什博弈不解释。。

#include<iostream>#include<cstdio>using namespace std;int main(){    int n,m;    int t;    cin>>t;    while(t--){        cin>>n>>m;        if(n%(m+1)==0)puts("Rabbit");        else puts("Grass");    }    return 0;}

HDU2149 Public Sale 

又是一道巴什博弈不解释。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int n,m;    while(~scanf("%d%d",&n,&m)){        if(n%(m+1)==0) printf("none\n");        else {            if(n<=m) {for(int i=n;i<=m;i++) {                if(i!=n) printf(" ");                printf("%d",i);            }printf("\n");}            else printf("%d\n",n%(m+1));        }    }    return 0;}

HDU1850 Being a Good Boy in Spring Festival  

经典的Nim游戏,所有的sg值异或等0就是必败态。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,a[nMax],sum;int ans=0;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    while(scanf("%d",&n),n){        sum=0;        for(int i=0;i<n;i++) scanf("%d",&a[i]),sum ^= a[i];        if(sum == 0) printf("0\n");        else {            ans =0;            for(int i=0;i<n;i++) {                sum ^= a[i];                //printf("%d %d\n",a[i],sum);                if(sum < a[i]) ans ++;                sum ^= a[i];            }            printf("%d\n",ans);        }    }    return 0;}

HDU2176 取(m堆)石子游戏 

  经典的NIM游戏,没有之一。。

#include<iostream>#include<cstring>#include<cstdio>using namespace std;int const nMax =200010;int n,m;int a[nMax];int main(){    while(~scanf("%d",&n),n)    {        int t=0;        for(int i=0;i<n;i++){            scanf("%d",&a[i]);            t^=a[i];        }        if(t==0){            puts("No");        }else {            puts("Yes");            for(int i=0;i<n;i++){                int b=a[i];                b^=t;                b^=0;                if(b<a[i])printf("%d %d\n",a[i],b);            }        }    }    return 0;}

HDU2177 取(2堆)石子游戏   

那个叫什么什么戚的博弈。。 结论和黄金分割数有关。。。

#include<iostream>#include<cstdio>#include<cstring>#include<map>using namespace std;int const nMax = 1000010;bool vis[nMax];map<int,int> Q;map<int,int> Q2;void init(){    Q.clear();    Q2.clear();    int a,b,c;    a=1,b=2;    //vis[1]=true;    Q[0]=0;    Q2[0]=0;    while(b<nMax){        if(vis[a]){            a++;            b++;        }else {          //  printf("a=%d b=%d\n",a,b);            Q[a]=b;            Q2[b]=a;            vis[a]=true;            vis[b]=true;            a++;            b+=2;        }    }    return ;}int main(){    init();    int n,m;    while(~scanf("%d%d",&n,&m),n||m)    {        if(Q.find(n)!=Q.end()){            if(Q[n]==m){            puts("0");            continue;            }        }        puts("1");        {            for(int i=1;i<=n;i++){                if(Q.find(n-i)!=Q.end())if(Q[n-i]==m-i){                    printf("%d %d\n",n-i,m-i);                }            }            //if(Q.find(n)!=Q.end())if(Q[n]<m)printf("%d %d\n",n,Q[n]);           if(n!=m) if(Q2.find(m)!=Q2.end())if(Q2[m]<n)printf("%d %d\n",Q2[m],m);            if(Q2.find(n)!=Q2.end())printf("%d %d\n",Q2[n],n);        }    }    return 0;}

POJ1067取石子游戏   

威佐夫博奕。。。 必输的局势就是ak = [k*(sqrt(5)+1)/2] , bk =k+ak;

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int check(int a,int b){    if(a>b) swap(a,b);    int k=b-a;    if(floor(k*((sqrt(5.0)+1)/2.0)) == a) return 0;    return 1;}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int a,b;    while(~scanf("%d%d",&a,&b)){        printf("%d\n",check(a,b));    }    return 0;}

POJ2505 A multiplication game  

YY出来的规律就是 1-9WIN 9+1 -- 2*9 LOSE 2*9+1 -- 9*2*9 WIN 9*2*9+1 -- 2*9*2*9WIN。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>LL n,b,e,s;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    while(~scanf("%I64d",&n)){        s=0;        b=1LL,e=9LL;        while(1){            if(n>=b && n<=e) break;            b=e+1;            if(s&1) e*=9;            else e*=2;            s++;        }        //cout<<s<<endl;        if(s&1) puts("Ollie wins.");        else puts("Stan wins.");    }    return 0;}

HDU2580 HDU2486 POJ3922 A simple stone game

  k倍动态消去减法游戏。 《从“k 倍动态减法游戏”出发探究一类组合游戏问题》文中提出的O(n)的算法,但是不适用于本题,参考网上神牛的思路就是构造出所有的必败态,然后就得出了必胜策略。

其实就是假设我们将所有的必败态看成序列,我们假设所有的n都可以由这些数的和组成,并且a[i]*k < a[i+1]。

我们假设n = a[i] + a[j] .我们去掉a[i] 因为a[j] > a[i]*k 所以对手取不完,就相当于k进制一样,无论对手怎样取,他还是会留下比之取值小的位数上仍然存在数,于是我们将那个数再次按以上规则选取,保证我们的必胜策略。我们的问题就是如何构造这样的序列。根据网上的质料,比较多的都是采用如下办法。

设a[i]为第i个数,b[i]表示当前可以组装到的最大的数,那么a[i+1]=b[i];b[i+1] = a[i]+b[t];其中满足max{t | a[t]*k < a[i] }于是我们就解决了这个问题。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 1001000#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int a[nMax],b[nMax];int top;int t,n,k,dp,cas=1;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&k);        int i=0,j=0;        a[0]=b[0]=0;        while(a[i]<n){            a[i+1]=b[i]+1;i++;            while(a[j+1]*k<a[i]) j++;            if(a[j]*k<a[i]) b[i]=a[i]+b[j];            else b[i]=a[i];        }        printf("Case %d: ",cas++);        if(n==a[i]) puts("lose");        else {            int ans=-1;            while(n){                if(n>=a[i]){                    ans=a[i];                    n-=a[i];                }                i--;            }            printf("%d\n",ans);        }    }    return 0;}

HDU4315 Climbing the Hill  

Nim游戏的变形“阶梯游戏”的再变形。。。然后各位可以GOOGLE一下你就知道,具体的就是将原来的位置一一配对,每一对相当于一个Nim游戏,然后就是sg异或什么的。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,k,a[nMax];int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    while(~scanf("%d%d",&n,&k)){        for(int i=0;i<n;i++) scanf("%d",&a[i]);        int sg=0;        for(int i=n-1;i>=0;i-=2){            if(i!=0) sg^=(a[i]-a[i-1]-1);            else {                if(k==2) sg^=(a[0]-1);                else    sg^=(a[0]);            }        }        if(k==1 || sg) printf("Alice\n");        else printf("Bob\n");    }    return 0;}

HDU3404 Switch lights  

 游戏积。。 一个比较复杂的东西,具体的见从“k 倍动态减法游戏”出发探究一类组合游戏问题》

真的是很神奇

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int Snim[17][17];void Nim_Init(){    int vis[400];    for(int i=0;i<17;i++) Snim[0][i]=Snim[i][0]=0;    for(int i=1;i<17;i++) Snim[1][i]=Snim[i][1]=i;    for(int x=2;x<17;x++){        for(int y=x;y<17;y++){            CLR(vis);            for(int a=0;a<x;a++){                for(int b=0;b<y;b++){                    vis[Snim[a][y]^Snim[x][b]^Snim[a][b]]=1;                }            }            for(int i=0;i<400;i++) if(!vis[i]) {Snim[x][y]=Snim[y][x]=i;break;}        }    }}template<class T>T Nim_Multi(T x,T y){    if(x<y) return Nim_Multi(y,x);    if(x<=16) return Snim[x][y];    T M=1,l=1;    while(1){        M=1<<l;        if(x>=M && x<(1<<(l<<1)))break;        l<<=1;    }    T p,q,s,t;    p=x/M,q=x%M;    s=y/M,t=y%M;    T c1=Nim_Multi(p,s);    T c2=Nim_Multi(p,t)^Nim_Multi(q,s);    T c3=Nim_Multi(q,t);    return ((c1^c2)*M)^c3^Nim_Multi_Power(M/2,c1);}template<class T>T Nim_Multi_Power(T x,T y){    if(x<y) return Nim_Multi(y,x);    if(x<=16) return Snim[x][y];    T M=1,l=1;    while(1){        M=1<<l;        if(x>=M)break;        l<<=1;    }    T p,s,t;    p=x/M;    s=y/M,t=y%M;    T d1 = Nim_Multi_Power(p,s);    T d2 = Nim_Multi_Power(p,t);    return M*(d1^d2)^Nim_Multi_Power(M/2,d1);}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    Nim_Init();    int t,n,x,y,sg;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        int sg=0;        while(n--){            scanf("%d%d",&x,&y);            sg ^= Nim_Multi((LL)x,(LL)y);        }        printf("%s\n",sg?"Have a try, lxhgww.":"Don't waste your time.");    }    return 0;}

贴上我的nim积模板:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int Snim[17][17];void Nim_Init(){    int vis[400];    for(int i=0;i<17;i++) Snim[0][i]=Snim[i][0]=0;    for(int i=1;i<17;i++) Snim[1][i]=Snim[i][1]=i;    for(int x=2;x<17;x++){        for(int y=x;y<17;y++){            CLR(vis);            for(int a=0;a<x;a++){                for(int b=0;b<y;b++){                    vis[Snim[a][y]^Snim[x][b]^Snim[a][b]]=1;                }            }            for(int i=0;i<400;i++) if(!vis[i]) {Snim[x][y]=Snim[y][x]=i;break;}        }    }}template<class T>T Nim_Multi(T x,T y){    if(x<y) return Nim_Multi(y,x);    if(x<=16) return Snim[x][y];    T M=1,l=1;    while(1){        M=1<<l;        if(x>=M  && x<(1<<(l<<1)) )break;        l<<=1;    }    T p,q,s,t;    p=x/M,q=x%M;    s=y/M,t=y%M;    T c1=Nim_Multi(p,s);    T c2=Nim_Multi(p,t)^Nim_Multi(q,s);    T c3=Nim_Multi(q,t);    return ((c1^c2)*M)^c3^Nim_Multi_Power(M/2,c1);}template<class T>T Nim_Multi_Power(T x,T y){    if(x<=16) return Snim[x][y];    T M=1,l=1;    while(1){        M=1<<l;        if(x>=M && x<(1<<(l<<1)))break;        l<<=1;    }    T p,s,t;    p=x/M;    s=y/M,t=y%M;    T d1 = Nim_Multi_Power(p,s);    T d2 = Nim_Multi_Power(p,t);    return M*(d1^d2)^Nim_Multi_Power(M/2,d1);}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    Nim_Init();    return 0;}

HDU1404 Digital Deletions  

由于串的长度极短而且第一位为0的话是必赢的,所以每种第一个不是0的串就对应唯一的0-999999中的一个整数,我们将其状态压缩,然后就是递推求出每个值是否是必胜的。。。就ok了。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 1000000#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int win[nMax];int length(int n){    int ans=0;    while(n){        ans ++;        n/=10;    }    return ans;}void f(int n){    int len = length(n);    for(int i=0;i<len;i++) {        int base = 1;        for(int j=0;j<i;j++) base*=10;        int m=n;        int cur = m%(base*10)/base;        while(cur<9){            win[m+base]=1;            m+=base;            cur++;        }    }    if(len<6){        int m=n,base=1;        for(int i=len;i<6;i++){            m*=10;            for(int j=0;j<base;j++){                win[m+j]=1;            }            base*=10;        }    }}void init(){    CLR(win);win[0]=1;    for(int i=1;i<nMax;i++) if(win[i]==0) f(i);}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int n,ok;    char s[10];    init();    while(gets(s)){        if(s[0]=='0') ok=1;        else {            n=0;            for(int i=0;s[i];i++) {                n = n*10 + s[i]-'0';            }            ok=win[n];        }        printf("%s\n",ok==0?"No":"Yes");    }    return 0;}

HDU3863 No Gambling 

 先手必胜。。具体原因不详~~~


#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    while(scanf("%d",&n),n!=-1){        printf("I bet on Oregon Maple~\n");    }    return 0;}

HDU3389 Game 

 假设你已经懂得阶梯博弈,不懂的请google之。 我们发现在模6的剩余下 0-3 1-2 4-5 这些事可以互相转移的。

看看这组数 1 2 3 4 5 0 1 2 3 4 5 0 1 2 。。。。。 我们考虑从2->1,0->3,5->4 的转移叫做移除,那么最后的sg值就是模6下余数为2,0,5的那个位置的值得异或。。。

这个和阶梯博弈基本等价,是一样的思路就是。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,t,a,cas=1;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    scanf("%d",&t);    while(t--){        scanf("%d",&n);        int sg=0;        for(int i=1;i<=n;i++) {            scanf("%d",&a);            if(i%6==0 || i%6==2 || i%6==5) sg ^= a;        }        printf("Case %d: %s\n",cas++,sg==0?"Bob":"Alice");    }    return 0;}

HDU1525 Euclid's Game 

有一个比较显然的地方就是若状态是(a,b) 那么她必然会转移到状态(b,a%b)。 那么我们来看看怎样求状态(a,b)的输赢状态。我们设k=a/b,如果递归求出(b,a%b)的状态是sg(b,a%b)=0,那么我们肯定一次奖(a,b) -> (b,a%b) 此时sg(a,b)=1。否则sg(b,a%b)=1,那么我们肯定不希望走到(b,a%b)而让对手获胜。但是如果k=1,我们就不得不走到那个位置,此时sg(a,b)=0;否则我们就是将(a,b) -> (a-(k-1)*b,b) 那么对手将不得不走到(b,a%b) ,此时sg(a,b)=1;

综上:

if sg(b,a%b)==0 ==>  sg(a,b)=1;

else 

k = a/b

if k==1 sg(a,b)=0;

else     sg(a,b)=1;

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int dfs(int a,int b){    if(b==0) return 0;    int k=a/b;    int s=dfs(b,a%b);    if(s==0) return 1;    if(k==1) return 0;    return 1;}int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int a,b;    while(scanf("%d%d",&a,&b),a||b){        if(a<b) swap(a,b);        if(dfs(a,b)) puts("Stan wins");        else puts("Ollie wins");    }    return 0;}

HDU3544 Alice's Game 

  我感觉我本来理解错题意了,这两人切蛋糕并且只能在新切出来的中做选择继续切,那么其实每个人都会选刚才切出来比较小的当中切,并且都会希望自己切的两份尽量相同,这样对手选的尽量大。很神奇的博弈。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 1001#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int t,n,a[nMax],cas=1;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        LL s1=0,s2=0;        for(int i=0,x,y;i<n;i++) {            scanf("%d%d",&x,&y);            while(x>1 && y>1) {                x>>=1,y>>=1;                s1++,s2++;            }            if(x==1) s2+=y-1;            else     s1+=x-1;        }        printf("Case %d: %s\n",cas++,s1>s2?"Alice":"Bob");    }    return 0;}

HDU1538 A Puzzle for Pirates   

经典的海盗分金币问题。。。 智商捉急啊。。。  推荐参考大牛BLOG 大家好,我是大牛。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<set>#include<queue>#include<map>using namespace std;#define FOR(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define DOR(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)#define CLR(a) memset((a),0,sizeof((a)))#define pb push_back#define mp make_pair#define ins insert#define F first#define S second#define bug puts("Oh Here!");#define nMax 10010#define oo 0x7fffffff#define eps 1e-8#define LL long long#define Vec vector<int>#define Pai pair<int,int>int n,m,p;int main(){#ifndef ONLINE_JUDGE//    freopen("input.txt","r",stdin);#endif    int t;    scanf("%d",&t);    while(t--){        scanf("%d%d%d",&n,&m,&p);        if(n<=2*m+1) {            if(p%2==n%2) {                if(p==n) printf("%d\n",m-(n+1)/2+1);                else printf("1\n");            }else printf("0\n");        }else {            int k=1,l=2;            while(1){                if(n<=2*m+l) break;                k++;l<<=1;            }            if(n==2*m+l) printf("0\n");            else {                if(p<=2*m+l/2) printf("0\n");                else printf("Thrown\n");            }        }    }    return 0;}

秀一下优越。。