USTC 1130 New Game

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;

}

你可能感兴趣的:(game)