USTC_1130
时隔多日,回过头在再做这个题目时终于AC了,于是顿时觉得能力的提升确实需要时间的积淀。
首先,如果Alice会输,那么各个棋子所在位置的sg函数值的异或必然为0,于是我们可以先预处理出各个节点的sg函数值。
至于求方案,一开始的想法就是去dp了,比如用f[i][j][k]表示到第i个节点时放了j个棋子,且它们异或值为k的方案总数。这样i的上限是100,j是10000,k是128,这样的复杂度显然是不能承受的。
我们联想到异或的性质,偶数个同一个数的异或为0,因此,整个局面的sg函数值,实际上只与每个节点上棋子数目的奇偶性有关,而剩下的棋子则两个两个的看成一组,放在哪里就无所谓了,可以用组合数算出方案数的。
于是我们只要用f[i][j][k]表示到第i个节点时奇数个棋子的节点数为j,它们的异或值为k的的方案总数。这样j的上限就是100了。之后对于每个f[N][j][0],如果S-j是偶数,就用组合数算一下剩下的棋子摆放的方案数,再和f[N][j][0]乘起来之后,加到最终结果里即可。
#include<stdio.h> #include<string.h> #define MAXD 110 #define MAXM 10010 #define MOD 1000000007 int N, M, S, U, V, e, first[MAXD], next[MAXM], v[MAXM], ny[MAXD], sg[MAXD], ch[MAXD][MAXD], f[MAXD][MAXD][130]; void exgcd(long long a, long long b, long long &x, long long &y) { if(b == 0) x = 1, y = 0; else exgcd(b, a % b, y, x), y -= x * (a / b); } void prepare() { int i; long long x, y; for(i = 1; i <= 100; i ++) { exgcd(i, MOD, x, y); x = (x % MOD + MOD) % MOD; ny[i] = x; } } long long comb(int n, int m) { int i; long long ans = 1; for(i = n - m + 1; i <= n; i ++) ans = ans * i % MOD; for(i = 2; i <= m; i ++) ans = ans * ny[i] % MOD; return ans; } void add(int x, int y) { v[e] = y; next[e] = first[x], first[x] = e ++; } void init() { int i, x, y; scanf("%d%d%d", &N, &M, &S); e = 0; memset(first, -1, sizeof(first)); for(i = 0; i < M; i ++) { scanf("%d%d", &x, &y); ++ x, ++ y; add(x, y); } } void dfs(int cur) { int i; memset(ch[cur], 0, sizeof(ch[cur])); for(i = first[cur]; i != -1; i = next[i]) { if(sg[v[i]] == -1) dfs(v[i]); ch[cur][sg[v[i]]] = 1; } for(i = 0; ch[cur][i]; i ++); sg[cur] = i; } void solve() { int i, j, k; long long ans = 0; memset(sg, -1, sizeof(sg)); for(i = 1; i <= N; i ++) if(sg[i] == -1) dfs(i); memset(f[0], 0, sizeof(f[0])); f[0][0][0] = 1; for(i = 1; i <= N; i ++) for(j = 0; j <= i; j ++) for(k = 0; k <= 128; k ++) f[i][j][k] = (f[i - 1][j][k] + f[i - 1][j - 1][k ^ sg[i]]) % MOD; for(i = 0; i <= N; i ++) if((S - i) % 2 == 0) ans = (ans + f[N][i][0] * comb((S - i) / 2 + N - 1, N - 1)) % MOD; printf("%lld\n", ans); } int main() { int t; prepare(); scanf("%d", &t); while(t --) { init(); solve(); } return 0; }