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;
}
秀一下优越。。