Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

AT2390 Games on DAG

题意

\(n\) 个点 \(m\) 条边的 DAG,每条边 \((u,v)\)\(u<v\)\(1,2\) 号点各一个石头,Alice 和 Bob 轮流每次沿边移动一个石头,不能动者输。求所有连边子集中先手胜的情况。两个石头可以重合。\(n\leq 15\)

思路

发现对于两个石头的 SG 函数是独立的,输者两个石头 SG 函数异或值为 0,那么先手胜的情况就是所有情况减去这种情况。

对于所有 SG 函数为 \(v\) 的点,它们必须向 SG 函数小于 \(v\) 的所有点连至少一条边,对大于 \(v\) 的连边没有约束,并且互相不能连边。

所以我们可以枚举当前图的 SG 函数为 0 的点,这样所有其他点都至少向它们连一条边,而它们之间不连边,它们向其他点连边任意。于是对于剩下点的连通子图,我们又可以将所有点的 SG 函数减 1,使它又可以枚举 SG 函数为 0 的点。

于是我们可以 DP。设 \(f_S(1,2\in S)\) 为对于 \(S\) 所有连通子图满足 1,2 SG 函数相等的方案数。

转移时枚举 \(S\) 的子集 \(T\) 为 SG 函数不为 0 的点,使 \(1,2\in T\)\(1,2\not \in T\)。对于前者情况,\(T\) 对于 \(S\) 的补集为 SG 函数为 0 的点,从 \(f_T\) 转移即可。对于后者情况,1,2 SG 函数为 0,\(T\) 中的边随便连。

DP 前预处理出所有集合被每个点的连边条数。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=x*10+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=15,mod=1e9+7;
int n,m,a[maxn][maxn],f[1<<maxn],c[1<<maxn][maxn],pow[maxn*maxn];
inline void work(){
n=read(),m=read();
pow[0]=1;for(int i=1;i<=m;i++) pow[i]=(pow[i-1]<<1)%mod;
for(int x,y,i=1;i<=m;i++) x=read()-1,y=read()-1,a[x][y]=1;
for(int d=1;d<1<<n;d++){
int j=0;
while(~d>>j&1)++j;
for(int x=0;x<n;x++) c[d][x]=c[d^1<<j][x]+a[x][j];
}
for(int d=0;d<1<<n;d++) if((d&3)==3){
f[d]=1;
for(int t=d&(d-1);t;--t&=d) if((t&1)==(t>>1&1)) if(t&1){
int res=1;
for(int i=0;i<n;i++) if(t>>i&1) res=1ll*res*(pow[c[d^t][i]]-1)%mod;
else if(d>>i&1) res=1ll*res*pow[c[t][i]]%mod;
f[d]=(f[d]+1ll*res*f[t])%mod;
}else{
int res=1;
for(int i=0;i<n;i++) if(t>>i&1) res=1ll*res*(pow[c[d^t][i]]-1)%mod*pow[c[t][i]]%mod;
else if(d>>i&1) res=1ll*res*pow[c[t][i]]%mod;
f[d]=(f[d]+res)%mod;
}
}
printf("%d\n",(pow[m]-f[(1<<n)-1]+mod)%mod);
}
}
signed main(){
star::work();
return 0;
}

给小狼留言