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;

}

你可能感兴趣的:(poj)