《博弈论》

尼姆博弈:

一:给定n堆石子,每次可以从一堆中取任意数量个,最后一个取完的获胜。

二:给定n堆石子,每次可以从一堆中取最多k个,最后一个取完的获胜。

三:给定n堆石子,每次可以选最多k堆,每堆可以取任意数量个,最后一个取完的获胜。

Solution:

一:这是最经典的一种尼姆博弈,先手必胜态为所有堆石子数异或后答案不为0.否则为必败态。

二: 对每堆的石子数模上(k + 1),就变成了经典的尼姆博弈类型。

三:这个问题又被称为nimk博弈,我们把每堆石头都表示成二进制,从每个二进制位去考虑。

统计每个二进制位上1的个数,如果满足每个二进制位上1的个数都可以 % (k + 1) = 0.那么先手必败。

反之,先手必胜。

巴什博弈:

有一堆n个石子,每次最多可以取k个,最后一个取完的获胜。

Solution:

如果n % (k + 1) == 0,那么后手只要每次和先手的数量凑成k + 1即可,那么后手必胜。

反之,先手先加上取模后的余数,然后就满足了 n % (k + 1) == 0的情况,此时先手变后手了,那么先手必胜。

威佐夫博弈:

给出两堆石子,有两种操作:1:从一堆中取任意个石子。2:从两堆中取相同数量的石子。最后一个取完的获胜。

结论:

黄金分割比:1.618 = (sqrt(5)+ 1) /  2 。//精度高

设两堆石子数为a,b。如果满足a = (a - b) * 1.618,先手必败,反之必胜。

https://www.cnblogs.com/csushl/p/10331498.html

HDU1079:Calendar Game

可以发现一共的日期并不多,所以考虑dp转移必胜态即可。其实这里也有规律可以找规律。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 998244353;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read() {
    int f = 1;LL x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

bool dp[105][15][35];
int a[15];
int cal(int year) {
    if(year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) return 29;
    return 28;
} 
void init() {
    a[1] = 31,a[2] = 0,a[3] = 31,a[4] = 30,a[5] = 31,a[6] = 30,a[7] = 31,a[8] = 31,a[9] = 30,a[10] = 31,a[11] = 30,a[12] = 31;
    dp[101][11][3] = 1;
    dp[101][11][2] = 0;
    dp[101][11][1] = 1;
    for(int i = 2001;i >= 1900;--i) {
        int L = 1,r = 12;
        if(i == 2001) r = 10;
        for(int j = r;j >= L;--j) {
            int ll = 1,rr = a[j];
            if(j == 2) rr = cal(i);
            for(int k = rr;k >= ll;--k) {
                int tag = 1;
                if(k != rr) tag &= dp[i - 1900][j][k + 1];
                else {
                    if(j == 12) tag &= dp[i - 1900 + 1][1][1]; 
                    else tag &= dp[i - 1900][j + 1][1];
                }
                if(i == 2001 && j == 10 && k >= 5) tag &= 1;
                else {
                    if(j == 12) tag &= dp[i - 1900 + 1][1][k];
                    else {
                        if(j == 1) {
                            int nxt = cal(i);
                            if(nxt >= k) tag &= dp[i - 1900][j + 1][k];
                        }
                        else {
                            if(a[j + 1] >= k) tag &= dp[i - 1900][j + 1][k];
                        }
                    }
                }
                if(tag == 0) dp[i - 1900][j][k] = 1; 
            }
        }

    }
}
void solve() {
    int x,y,z;scanf("%d %d %d",&x,&y,&z);
    printf("%s\n",dp[x - 1900][y][z] ? "YES" : "NO");
}
int main() {    
    init();
    int ca;scanf("%d",&ca);
    while(ca--) {
        solve();
    }
    system("pause");
    return 0;
}
View Code 

HDU1525:Euclid's Game

我们可以发现对于只能减去一倍的情况,是没有什么好说的只能老实去减。

然后就是对于多倍的情况,可以发现的是,有两个种操作,一种全部减去,先手变后手,另一种减去k - 1倍,那么下一个人只能减去剩下的一倍,先手依旧变先手。

所以对于多倍我们可以操作成对自己有利的情况,那么,很显然能决定答案的,就是最后一个多倍的情况。也就是说谁能先操作最后一个多倍,那么谁就能赢。

然后因为对于多倍我们可以决定下一次的先后手情况,那么很显然就说明第一个操作多倍的人,可以让自己也先操作下一个多倍。

那么我们就可以知道了,谁先操作第一个多倍,谁就可以永远第一个操作所有的多倍,也就可以获胜。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 998244353;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read() {
    int f = 1;LL x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

void solve() {
    int x,y;
    while(scanf("%d %d",&x,&y),x != 0 || y != 0) {
        int ta = 1;
        if(x < y) swap(x,y);
        if(x % y == 0) {printf("Stan wins\n");continue;}
        int g = 0;
        while(1) {
            if(x < y) swap(x,y);
            if(x % y == 0) {printf("%s\n",g == 0 ? "Stan wins" : "Ollie wins");break;}
            int k = x / y;
            if(k == 1) x -= y,g ^= 1;
            else {
                if(g == 0) {printf("Stan wins\n");break;}
                else {printf("Ollie wins\n");break;}
            }
        }
    }
}
int main() {    
    solve();
    system("pause");
    return 0;
}
View Code

HDU1564:Play a game

猜测了一下只和总个数有关,结果就是这样。

模拟了一下发现,不管怎么样先后手想去改变输赢情况,即棋子奇偶数,隔出去的数量总是偶数个,不会改变原来的奇偶情况。

所以只和原来的奇偶数有关。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 998244353;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read() {
    int f = 1;LL x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

void solve() {
    int n;
    while(scanf("%d",&n),n != 0) {
        printf("%s\n",n % 2 == 0 ? "8600" : "ailyanlu");
    }
}
int main() {    
    solve();
    system("pause");
    return 0;
}
View Code

HDU1846:Brave Game

巴什博弈的模型。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 998244353;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read() {
    int f = 1;LL x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

void solve() {
    int n,m;scanf("%d %d",&n,&m);
    if(m >= n) printf("first\n");
    else {
        if(n % (m + 1) == 0) printf("second\n");
        else printf("first\n");
    }
}
int main() {    
    int ca;scanf("%d",&ca);
    while(ca--) {
        solve();
    }
    system("pause");
    return 0;
}
View Code

HDU1847:Good Luck in CET-4 Everybody!

SG板子题。SG函数求一下即可。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int N = 1e4 + 5;
const int M = 1e3 + 5;
const double eps = 1e-10;
const LL Mod = 998244353;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read() {
    int f = 1;LL x = 0;char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
    return x*f;
}
inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
inline long long MUL(long long x,long long y) {return x * y % Mod;}

bool S[N];
int SG[N];
int f[10];
void init(int x) {
    memset(SG,0,sizeof(SG));
    for(int i = 1;i <= x;++i) {
        memset(S,0,sizeof(S));
        for(int j = 0;j <= 9 && f[j] <= i;++j) S[SG[i - f[j]]] = 1;
        for(int j = 0;;++j) if(!S[j]) {SG[i] = j;break;}
    }
}
void solve() {
    int n;
    f[0] = 1;
    for(int i = 1;i <= 9;++i) f[i] = f[i - 1] * 2;
    while(~scanf("%d",&n)) {
        init(n);
        printf("%s\n",SG[n] == 0 ? "Cici" : "Kiki");
    }
}
int main() {    
    solve();
    system("pause");
    return 0;
}
View Code

 

posted @ 2021-08-28 07:43  levill  阅读(158)  评论(0编辑  收藏  举报