POJ 2888 Magic Bracelet(Burnside引理,矩阵优化)

Magic Bracelet

Time Limit: 2000MS Memory Limit: 131072K
Total Submissions: 3731 Accepted: 1227

Description

Ginny’s birthday is coming soon. Harry Potter is preparing a birthday present for his new girlfriend. The present is a magic bracelet which consists of n magic beads. The are m kinds of different magic beads. Each kind of beads has its unique characteristic. Stringing many beads together a beautiful circular magic bracelet will be made. As Harry Potter’s friend Hermione has pointed out, beads of certain pairs of kinds will interact with each other and explode, Harry Potter must be very careful to make sure that beads of these pairs are not stringed next to each other.

There infinite beads of each kind. How many different bracelets can Harry make if repetitions produced by rotation around the center of the bracelet are neglected? Find the answer taken modulo 9973.

Input

The first line of the input contains the number of test cases.

Each test cases starts with a line containing three integers n (1 ≤ n ≤ 109gcd(n, 9973) = 1), m (1 ≤ m ≤ 10), k (1 ≤ k ≤ m(m − 1) ⁄ 2). The next k lines each contain two integers a and b(1 ≤ ab ≤ m), indicating beads of kind a cannot be stringed to beads of kind b.

Output

Output the answer of each test case on a separate line.

Sample Input

4
3 2 0
3 2 1
1 2
3 2 2
1 1
1 2
3 2 3
1 1
1 2
2 2

Sample Output

4
2
1
0

Source

POJ Monthly–2006.07.30, cuiaoxiang    
很好的一道题目。
做了这题才感觉对Burnside引理和polya定理有点深入了解。  
Burnside引理基础知识:http://wenku.baidu.com/view/57448c4e852458fb770b5695.html  
还不清楚的可以看看上面的链接,解释的很清楚。  
关于这题,给个解释的很清楚的http://hi.baidu.com/billdu/item/62319f2554c7cac9a5275a0d  
讲得很清晰  

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <iostream>
using namespace std;
const int MOD = 9973;
//矩阵
struct Matrix
{
    int mat[20][20];
    int n,m;
    Matrix(){}
    Matrix(int _n,int _m)
    {
        n = _n; m  = _m;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < m;j++)
                mat[i][j] = 0;
    }
    Matrix operator *(const Matrix &b)const
    {
        Matrix ret = Matrix(n,b.m);
        for(int i = 0;i < ret.n;i++)
            for(int j = 0;j < ret.m;j++)
            {
                for(int k = 0;k < m;k++)
                {
                    ret.mat[i][j] += mat[i][k]*b.mat[k][j];
                    ret.mat[i][j] %= MOD;
                }
            }
        return ret;
    }
    Matrix operator ^(int b)const
    {
        Matrix ret = Matrix(n,m),tmp = Matrix(n,m);
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
                tmp.mat[i][j] = mat[i][j];
            ret.mat[i][i] = 1;
        }
        while(b)
        {
            if(b&1)ret = ret*tmp;
            tmp = tmp*tmp;
            b >>= 1;
        }
        return ret;
    }
};
//求欧拉函数
long long eular(long long n)
{
    long long ans = n;
    for(int i = 2;i*i <= n;i++)
    {
        if(n % i == 0)
        {
            ans -= ans/i;
            while(n % i == 0)
                n /= i;
        }
    }
    if(n > 1)ans -= ans/n;
    return ans;
}
//快速幂,用来求逆元
long long pow_m(long long a,long long n,long long mod)
{
    long long ret = 1;
    long long tmp = a%mod;
    while(n)
    {
        if(n&1)
        {
            ret *= tmp;
            ret %= mod;
        }
        tmp *= tmp;
        tmp %= mod;
        n>>=1;
    }
    return ret;
}
//利用欧拉定理求逆元
long long inv(long long x,long long mod)//mod为素数
{
    return pow_m(x,mod-2,mod);
}

Matrix A,B;
int n,m;
//求x个元素对应的f
int NoChange(int x)
{
    B = A^x;
    int ans = 0;
    for(int i = 0; i < m;i++)
    {
        ans += B.mat[i][i];
        ans %= MOD;
    }
    return ans;
}
int solve()
{
    int ans = 0;
    for(int i = 1;i*i <= n;i++)
        if(n % i == 0)
        {
            ans = ans + eular(i)*NoChange(n/i)%MOD;
            ans %= MOD;
            if(n/i != i)
            {
                ans = ans + eular(n/i)*NoChange(i)%MOD;
                ans %= MOD;
            }
        }
    ans *= inv(n,MOD);
    return ans%MOD;
}
int main()
{
    int T;
    int k;
    int u,v;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        A = Matrix(m,m);
        for(int i = 0;i < m;i++)
            for(int j = 0;j < m;j++)
                A.mat[i][j] = 1;
        while(k--)
        {
            scanf("%d%d",&u,&v);
            u--;
            v--;
            A.mat[u][v] = A.mat[v][u] = 0;
        }
        printf("%d\n",solve());
    }
    return 0;
}

 

 

 

 

 

    原文作者:kuangbin
    原文地址: https://www.cnblogs.com/kuangbin/p/3207580.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞