HDU 1847Good Luck in CET-4 Everybody!
n个石子取2的次幂个,0为terminal position
P/N分析和求SG值方法都可以,找规律的话模3余0也能过
主要是为了练习SG的求法
#include <cstdio> #include <cstring> //单纯博弈型 也可用P/N分析法 int x[12],SG[1050]; bool vis[1050]; void init() { for (int i=0 ; i<11 ; ++i) x[i]=1<<i; SG[0]=0; for (int i=1 ; i<1002 ; ++i)//get Sprague-Grundy value; { memset (vis , 0 , sizeof(vis)); for (int j=0 ; x[j]<=i ; ++j) { vis[SG[i-x[j]]]=true; } for (int j=0 ; ; ++j) { if(!vis[j]){SG[i]=j;break;} } } for (int i=0 ; i<100 ; ++i) printf("num=%d sg=%d\n",i,SG[i]); } int main () { int n; init(); while (~scanf("%d",&n)) { if(SG[n])puts("Kiki"); else puts("Cici"); } return 0; }
HDU 3980 Paint Chain
n元环,每次取连续的m个元素,最先不能取者败。
可以考虑n<m和n>=m两种情况,第一种情况结果显然,第二种将取过1次后剩下的n-m元链进行求SG值,前m-1个状态的SG值明显为0,m为1,之后的状态取走m元素之后,会将剩下的2段分成2份(考虑0的情况),分别求其SG值,从而得到当前的状态的一个后继SG值。
#include <cstdio> #include <cstring> const int maxn=1005; int SG[maxn]; bool vis[maxn]; bool sg(int n , int m)//get SG value { memset(SG , 0 , sizeof(SG)); SG[m]=1; for (int i=m+1 ; i<=n ; ++i) { memset (vis , 0 , sizeof(vis)); for (int j=0 ; j<i-m ; ++j) { vis[SG[j]^SG[i-m-j]]=true; } for (int j=0 ; ; ++j) { if(!vis[j]){SG[i]=j;break;} } } //for (int i=0 ; i<=n ; ++i) //printf("%d %d \n",i,SG[i]); return SG[n]; } int main () { int cas; int n,m; scanf("%d",&cas); for (int I=1 ; I<=cas ; ++I) { scanf("%d%d",&n,&m); if(m>n)printf("Case #%d: abcdxyzk\n",I); else if(sg(n-m,m))printf("Case #%d: abcdxyzk\n",I); else printf("Case #%d: aekdycoin\n",I); } return 0; }
POJ 3537 Crosses and Crosses
给一个1*n的长方形格子,在格子里轮流画X,最先得到3个连续X的人即为winner
#include <cstdio> #include <cstring> const int maxn=2005; int SG[maxn]; bool vis[maxn]; void sg() { memset (SG , 0 , sizeof(SG)); SG[1]=1;SG[2]=1;SG[3]=1;//SG[4]=1; for (int i=4; i<maxn ; ++i) { memset (vis , 0 , sizeof(vis)); for (int j=2 ; j<i ; ++j) { if((i-j-1<2))vis[SG[j-2]^0]=true; else vis[SG[j-2]^SG[i-j-1-2]]=true; } for (int j=0 ; ; ++j) if(!vis[j]){SG[i]=j ; break;} } //for (int i=0; i<50 ; ++i) //printf("SG%d=%d\n",i,SG[i]); } int main () { sg(); int n; while (~scanf("%d",&n)) { if(SG[n])puts("1"); else puts("2"); } return 0; }
#include <cstdio> #include <cstring> const int maxm=2005000; const int maxn=1005; struct Edge { int v,next; }edge[maxm]; int head[maxn],cnt; void addedge(int u,int v) { edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } bool vis[maxn],visit[maxn][maxn];//for dfs for sg; int SG[maxn]; void dfs (int u) { if(~SG[u]) return ; //vis[u]=true; int p=head[u]; for ( ; ~p ; p=edge[p].next) { int v=edge[p].v; //printf("%d ",u); //if(vis[v])continue; dfs(v); visit[u][SG[v]]=true; } for (int i=0 ; true ; ++i) { if(!visit[u][i]){SG[u]=i;break;} } } int main () { int n,node,v,m,t; while (~scanf("%d",&n)) { memset (head , -1 , sizeof(head)); memset (SG , -1 , sizeof(SG)); cnt=0; for (int u=0 ; u<n ; ++u) { scanf("%d",&node); if(!node)SG[u]=0; for (int i=0 ; i<node ; ++i) { scanf("%d",&v); addedge(u , v); } } memset (vis , false , sizeof(vis)); memset (visit , false , sizeof(visit)); for(int i=0 ; i<n ; ++i) { if(vis[i])continue; dfs(i); } /*for (int i=0 ; i<n ; ++i) { printf("%d\t",SG[i]); }*/ while (scanf("%d",&m),m) { int nim=0; for(int i=0 ; i<m ; ++i) { scanf("%d",&t); nim^=SG[t]; } puts(nim?"WIN":"LOSE"); } } return 0; }
#include <cstdio> #include <algorithm> using namespace std; const int maxn=1005; int nim[maxn]; int n; int main () { int cas; scanf("%d",&cas); while (cas--) { scanf("%d",&n); int ans=0; nim[0]=0; for (int i=1 ; i<=n ; ++i) { scanf("%d",nim+i); } sort(nim,nim+n+1); for (int i=0 ; i<(n+1)/2 ; ++i) { ans^=(nim[n-2*i]-nim[n-2*i-1]-1); //printf("%d %d %d\n",nim[n-2*i],nim[n-2*i-1],ans); } puts(ans?"Georgia will win":"Bob will win"); } return 0; }
#include <cstdio> #include <cstring> int SG[105][105]; bool vis[5000]; /*棋盘上的2维SG递推,非组合游戏可以不用SG*/ /*输出格式很恶心*/ int main () { int l,w; SG[0][0]=0; for (int i=1 ; i<105 ; ++i) { SG[i][0]=i; for (int j=1 ; j<105 ; ++j) { SG[0][j]=j; if(i==j){SG[i][i]=i+1;continue;} memset (vis , 0 , sizeof(vis)); for (int k=0 ; k<j ; ++k) vis[SG[i][k]]=true; for (int k=0 ; k<i ; ++k) vis[SG[k][j]]=true; for (int k=1 ; k<=i&&k<=j ; ++k) vis[SG[i-k][j-k]]=true; for (int k=0 ; ; ++k) if(!vis[k]){SG[i][j]=k ; break;} } } /* for (int i=0 ; i<25 ; ++i) { for (int j=0 ; j<25 ; ++j) printf("%d ",SG[i][j]); puts(""); } */ while (~scanf("%d*%d",&l,&w)) { if(l==1 || w==1){printf("G will win\n");continue;} bool flag=false; bool first=false; for (int i=0 ; i<l ; ++i) { if(!SG[i][w-1]) { flag=true; if(first)printf(" "); printf("(%d,%d)",i,w-1); first=true; } } for (int i=0 ; i<w-1 ; ++i) { if(!SG[l-1][i]) { flag=true; if(first)printf(" "); printf("(%d,%d)",l-1,i); first=true; } } if(!flag)printf("G will win"); printf("\n"); } return 0; }
#include <cstdio> #include <cstring> #include <cmath> #define abs(a) (a)>(0)?(a):(-(a)) #define min(a,b) (a>b?b:a) const int maxn=100000+123; typedef int typen; typen a[maxn]; typen count[maxn]; const int maxp = 5000; int prime[maxp + 1];//prime[0] is the counter int getPrime() { memset (prime, 0, sizeof (prime)); for (int i = 2 ; i <= maxp ; i++) { if (!prime[i]) prime[++prime[0]] = i; for (int j = 1; j <= prime[0] && prime[j] * i <= maxp ; j++) { prime[prime[j]*i] = 1; if (i % prime[j] == 0) break; } } return prime[0]; } int getFactors(typen x) { int facCnt = 0; typen tmp = x; for(int i = 1; prime[i]*prime[i] <= tmp ; ++i) { if(tmp % prime[i] == 0) { while(tmp % prime[i] == 0) tmp /= prime[i],++facCnt; } } if(tmp != 1) ++facCnt; return facCnt; } int cas=0; int main () { int n; getPrime(); while ( ~scanf("%d",&n) ) { memset (count , 0 , sizeof(count)); int sum=0; for (int i=0 ; i<n ; ++i) { scanf("%d",a+i); count[i]=getFactors(a[i]); } for (int i=0 ; i<n ; ++i) { sum^=count[i]; } if(sum) { int i; for (i=0 ; i<n ; ++i)//从 { if((sum^count[i])<count[i])break; } printf("Test #%d: Alice %d\n",++cas,i+1); } else printf("Test #%d: Bob\n",++cas); } return 0; }