题目大意

现在有两个人在一个n个结点的有向图上玩一个双人游戏,保证图中无环和自圈。游戏的规则如下:
1.初始的时候$i$号点有一个正权值$value_i$
2.两名玩家依次操作,每个玩家在当前回合可以选择一个具有如下性质的点
-该点的权值为正
-该点具有至少一条出边
如果不存在这样子的点,那么当前回合的玩家输掉整局游戏
3.当某名玩家选定一个点以后,将该点的$value$减一,并将$K_i$个该点出边连向的点的$value$加一,这$K_i$个点由当前玩家选择,并允许选择重复的点。
现在给出整个有向图和$K_i$,每次询问给定每个点的$value$,判断先手玩家是否存在必胜策略。

$n\leq 100$,每个点的出边数量不超过$17$。

题解

由于每一步操作只令$value_i$的值$-1$,所以可以把“在$x$点有$1$的权值”看做“以$x$点为起点开始一局游戏”。

考虑在$x$点做两局游戏一定是后手赢,因为不论执先手的人在某一局子游戏进行操作,后手只需要在另一局进行对称操作即可。

所以只关心$value$的奇偶性。

由于每一个点的出边不超过$17$,所以以一个点为起点的子游戏,其后继是可枚举的。

具体的,对于没有出边的点$x,Sg_x=0$。

否则枚举每一条出边是否改变出边指向的点$y$的游戏的次数的奇偶性,将游戏次数奇偶性被改变的后继的点集记为$S$,设这$S$个点的$Sg$值的异或和为$F_S$,则$$Sg_x=mex\{F_S\}(|S|\leq K_i,|S|\equiv K_i\mod x)$$

即枚举每一个$x$点出发能到达的所有后继状态,每一个后继状态都有若干个子游戏组成,其根据$Sg$定理,$Sg$值为每一个子游戏的$Sg$值异或和,所以对所有个后继状态$Sg$值求$mex$即可。

对于每一次询问,对于所有的$x$满足以$x$点进行了奇数次游戏,则将这些$Sg_x$异或起来和,若为$0$则先手必败,负责先手必胜。

复杂度为$O(T(2^{17}n+Qn))$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200
#define N 540000
using namespace std;
int read(){
int nm=0,fh=1; int cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
int n,m,sz[M],to[M][20],tmp,K[M],val,sg[M],bt[N],G[N],F[N];
void link(int x,int y){to[x][++sz[x]]=y;} bool vs[N];
void DP(int x){
if(sg[x]!=-1) return; if(!sz[x]){sg[x]=0;return;}
for(int i=1;i<=sz[x];i++) DP(to[x][i]);
for(int i=1;i<=sz[x];i++) G[1<<(i-1)]=sg[to[x][i]];
int MAXN=(1<<sz[x]); F[0]=sg[x]=0;
for(int i=1;i<MAXN;i++) F[i]=(F[i^(i&(-i))]^G[i&(-i)]);
for(int i=0;i<MAXN;i++) if(bt[i]<=K[x]&&!((K[x]^bt[i])&1)) vs[F[i]]=true;
while(vs[sg[x]]) ++sg[x]; for(int i=0;i<MAXN;i++) vs[F[i]]=false;
}
int main(){
for(int i=1;i<(1<<19);i++) bt[i]=bt[i>>1]+(i&1);
memset(vs,false,sizeof(vs));
for(int Qs=read(),nq=1;nq<=Qs;nq++,putchar('\n')){
printf("Game#%d:\n",nq),memset(sg,-1,sizeof(sg));
n=read(),m=read(),memset(sz,0,sizeof(sz));
for(int i=1;i<=m;i++){int x=read(),y=read();link(x+1,y+1);}
for(int i=1;i<=n;i++) K[i]=read();
for(int i=1;i<=n;i++) DP(i);
for(int rm=1,rs=0,Qr=read();rm<=Qr;rm++,rs=0){
for(int i=1;i<=n;i++) val=read(),rs^=((val&1)*sg[i]);
printf("Round#%d: ",rm),puts(rs?"WINNING":"LOSING");
}
}
return 0;
}

最新文章

  1. Storm的ack机制在项目应用中的坑
  2. windows phone SDK 8.0 模拟器异常 0x89721800解决办法
  3. Using Sessions and Session Persistence---reference
  4. JetBrains IntelliJ IDEA for Mac 15.0 破解版 – Mac 上强大的 Java 集成开发工具
  5. opencv使用convexityDefects计算轮廓凸缺陷
  6. GPRS优点介绍及GPRS上网相关知识(转)
  7. 201521123035《Java程序设计》第二周学习总结
  8. Echarts后台封装option对象
  9. FlappyBird Pygame
  10. TypeScript 中非代码模块的导入
  11. 使用ethtool显示硬件PHY信息
  12. embed 引入网上视频
  13. 芯灵思Sinlinx A64 Linux&amp;qt编译安装
  14. 【pygame游戏编程】第一篇-----创建一个窗口
  15. SPLAY,LCT学习笔记(一)
  16. XML系列之--对电文格式XML的简单操作(三)
  17. Listview多tab上滑悬浮
  18. NLP-python 自然语言处理01
  19. ubuntu16.04 安装power shell
  20. June 24th 2017 Week 25th Saturday

热门文章

  1. 谷歌高管无意中透露Google Glass未获得成功的原因
  2. &lt;mark&gt;元素----黄色背景
  3. IOS程序国际化
  4. Java线程面试题:子线程先运行 2 次,然后主线程运行 4 次,如此反复运行 3 次
  5. C++中面向对象的理解
  6. CSS3 线性渐变(linear-gradient)
  7. 单向HASH——MurmurHash
  8. One Person Game(概率+数学)
  9. 忘记apple id如何更新应用?
  10. did not find a matching property (tomcat+Eclipse 报错)