HDU_5724_状态压缩的sg函数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5724
题目大意:n行20列的棋盘,对于每行,如果当前棋子右边没棋子,那可以直接放到右边,如果有就跳过放到其后面的第一个空位子,A先操作,最后谁无法操作则输,给定每行棋子状态,问先手是否必胜
题目分析:组合博弈问题,直接sg函数,因为列只有20,可以状压搞,枚举每个状态,找到该状态下可行的操作然后标记,sg函数结论可参考sg函数和sg定理
sg函数还需学习。
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #include<map> using namespace std; int sg[(2<<20)+5],vis[25]; int getSg(int sta) { memset(vis,0,sizeof(vis)); for(int i=20; i>=0; i--) { if(sta&(1<<i)) { int tmp=sta; for(int j=i-1; j>=0; j--) if(!(sta&(1<<j))) { tmp^=(1<<i)^(1<<j); vis[sg[tmp]]=1; break; } } } for(int i=0; i<=20; i++) if(vis[i]==0) return i; return 0; } int main() { int t; memset(sg,0,sizeof(sg)); for(int i=0; i<(1<<20); i++) sg[i]=getSg(i); scanf("%d",&t); while(t--) { int n,ans=0; scanf("%d",&n); for(int i=0; i<n; i++) { int m,sta=0; scanf("%d",&m); while(m--) { int pos; scanf("%d",&pos); sta|=(1<<(20-pos)); } ans^=sg[sta]; } if(ans) printf("YES\n"); else printf("NO\n"); } return 0; }