• 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;
    }
  • 相关阅读:
    面向对象的三大特性(封装、继承、多态)-----继承
    前端---HTML
    几个排序算法的python实现
    构造方法关键字---this
    构造方法中关键字-- super
    多态(instanceof)
    接口
    抽象
    继承(重写与重载对比)
    数组的逆序
  • 原文地址:https://www.cnblogs.com/staginner/p/2512451.html
Copyright © 2020-2023  润新知