博弈论大作战之 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;}
秀一下优越。。
- 博弈论大作战之 PART1
- 博弈论大作战之 PART2
- python大作战之排序
- python大作战之集合
- python大作战之生成器
- java之旅之习题大作战
- 家有千金之零花钱大作战
- 省钱大作战之图片色彩
- 电视剧推荐之求婚大作战
- java之核心问题大作战
- python序列大作战之可变序列
- python大作战之迭代器初级篇
- 自考路之C++大作战(上)
- 自考路之C++大作战(中)
- 自考路之C++大作战(下)
- 数字大作战:宽带报障系列之错误633
- 刷题记之代码能力大作战一
- 刷题记之代码能力大作战二
- 15 Command Line Tools to Monitor Linux Performance
- Android 制作引导层 使用透明的activity
- uva 11178 Morley's Theorem 点线
- 使用精确小数时注意项
- 何时需要强制类型转换(一)
- 博弈论大作战之 PART1
- rac安装快速配置脚本
- HDU 4578 Transformation(13年杭州邀请赛-C题-线段树)
- Vector介绍
- 黑马程序员--懒汉式(面试题)
- git 相关
- 老码农教你学英语
- 来自极客标签10款最新设计素材-系列十三
- LigerUI 控件中的date一个小BUG处理。