博弈论大作战之 PART1

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;
}

秀一下优越。。


    

  
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值