例题Ⅰ:
题解:时间复杂度 O(n*3^n)
int n, m, a[N][N]; // 邻接矩阵
int twoP[N * N], dp[1 << N], cnt[1 << N][N];
// dp[I]记录集合I在必败的前提下所有的边组合方式, cnt[i][j]记录j到集合i的边数
void solve()
{
cin >> n >> m;
twoP[0] = 1;
for (int i = 1; i <= m; ++i)
twoP[i] = 2 * twoP[i - 1] % mod;
for (int i = 1, x, y; i <= m; ++i)
{
cin >> x >> y;
a[x][y] = 1;
}
for (int U = 1; U < 1 << n; ++U)
{
int j = __builtin_ffs(U) - 1; // 最后一位1的位置
for (int u = 0; u <= n; ++u) // 预处理cnt
cnt[U][u] = cnt[U ^ 1 << j][u] + a[u + 1][j + 1];
}
for (int U = 0; U < 1 << n; ++U) // 枚举全集子集U
{
if((u & 3) != 3 && (u & 3) != 0) continue;
dp[U] = 1; // 初始化集合U必败态的总数
for (int T = U & (U - 1); T; --T &= U) // 枚举U的子集T
{
if ((T & 1) != (T >> 1 & 1)) // 1,2都在或都不在T
continue;
int S = U ^ T, coef = 1; // S是U - T
for (int i = 0; i < n; ++i)
{
if (T >> i & 1)
coef = (ll)coef * twoP[cnt[S][i]] % mod; // T到S随便选边
if (S >> i & 1)
coef = (ll)coef * (twoP[cnt[T][i]] - 1) % mod; // S到T至少选一条边
}
//dp[T]内部没有边,只有空集一种情况
dp[U] = (dp[U] + (ll)coef * dp[S] % mod) % mod;
}
}
cout << (twoP[m] - dp[(1 << n) - 1] + mod) % mod << endl;
}




