• POJ 2888 Magic Bracelet


    POJ_2888

        自己一开始学polya的时候还是太浮躁了,只是相当于背过了个公式而已,其实根本没建立在理解的基础之上。今天踏下心来又看了一遍黑书,终于能够自己根据burnside引理来推导出polya公式了。

        解决这个题目首先要了解burnside引理的内容,接着就是用dp的方法去具体计算黑书上所谓的C(f)(在置换f下保持不变的着色方案数)了。最后的结果是C(f)的平均值,也就是C(f)/N,由于9973和N互质,所以可以先求N的逆元,进一步就可以得到(C(f)/N)%9973的值了。

        推荐一个此题讲解得非常详细的博客:http://hi.baidu.com/billdu/item/62319f2554c7cac9a5275a0d

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #define MAXD 40010
    #define MAXM 15
    #define MOD 9973
    using namespace std;
    int N, M, K, prime[MAXD], isprime[MAXD], P, g[MAXM][MAXM], d[MAXD], D;
    struct Matrix
    {
        int a[MAXM][MAXM];
        void init()
        {
            memset(a, 0, sizeof(a));
        }
    }unit, mat;
    void prepare()
    {
        int i, j, k = 40000;
        P = 0;
        memset(isprime, -1, sizeof(isprime));
        for(i = 2; i <= k; i ++)
            if(isprime[i])
            {
                prime[P ++] = i;
                for(j = i * i; j <= k; j += i)
                    isprime[j] = 0;
            }
    }
    int euler(int n)
    {
        int i, ans, x;
        ans = x = n;
        for(i = 0; i < P && prime[i] * prime[i] <= n; i ++)
            if(x % prime[i] == 0)
            {
                ans = ans / prime[i] * (prime[i] - 1);
                while(x % prime[i] == 0)
                    x /= prime[i];
            }
        if(x > 1)
            ans = ans / x * (x - 1);
        return ans;
    }
    void exgcd(int a, int b, int &x, int &y)
    {
        if(b == 0)
            x = 1, y = 0;
        else
            exgcd(b, a % b, y, x), y -= x * (a / b);
    }
    Matrix multiply(Matrix &x, Matrix &y)
    {
        int i, j, k;
        Matrix z;
        z.init();
        for(i = 0; i < M; i ++)
            for(k = 0; k < M; k ++)
                if(x.a[i][k])
                {
                    for(j = 0; j < M; j ++)
                        if(y.a[k][j])
                            z.a[i][j] = (z.a[i][j] + x.a[i][k] * y.a[k][j]) % MOD;
                }
        return z;
    }
    void init()
    {
        int i, x, y;
        scanf("%d%d%d", &N, &M, &K);
        memset(g, -1, sizeof(g));
        for(i = 0; i < K; i ++)
        {
            scanf("%d%d", &x, &y);
            -- x, -- y;
            g[x][y] = g[y][x] = 0;
        }
    }
    void divide(int n)
    {
        int i, j;
        D = 0;
        for(i = 1; i * i <= n; i ++)
            if(n % i == 0)
            {
                d[D ++] = i;
                if(n / i != i)
                    d[D ++] = n / i;
            }
        sort(d, d + D);
    }
    void powmod(Matrix &unit, Matrix &mat, int n)
    {
        while(n)
        {
            if(n & 1)
                unit = multiply(mat, unit);
            n >>= 1;
            mat = multiply(mat, mat);
        }
    }
    void solve()
    {
        int i, j, x, y, n, ans = 0;
        divide(N);
        for(i = 0; i < D; i ++)
        {
            n = euler(N / d[i]) % MOD;
            for(x = 0; x < M; x ++)
                for(y = 0; y < M; y ++)
                    mat.a[x][y] = -g[x][y];
            unit = mat;
            powmod(unit, mat, d[i] - 1);
            for(j = 0; j < M; j ++)
                ans = (ans + n * unit.a[j][j]) % MOD;
        }
        exgcd(N, MOD, x, y);
        x = (x % MOD + MOD) % MOD;
        ans = (ans * x) % MOD;
        printf("%d\n", ans);
    }
    int main()
    {
        int t;
        prepare();
        scanf("%d", &t);
        while(t --)
        {
            init();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    浅谈Java设计模式——状态模式(State)
    浅谈Java设计模式——解释器模式(Interpreter)
    浅谈Java设计模式——备忘录模式(Memento)
    struts2 标签
    Struts2 Web资源获取
    链接
    Struts2数据封装机制
    struts学习
    位运算
    归并排序求逆序对
  • 原文地址:https://www.cnblogs.com/staginner/p/2505635.html
Copyright © 2020-2023  润新知