HOJ Magic Bracelet polya置换第二个里程碑

Magic Bracelet



Submitted : 37, Accepted : 25

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 ofn magic beads. The arem 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 ≤ 109, gcd(n, 9973) = 1), m (1 ≤m ≤ 10),k (1 ≤ km(m − 1) ⁄ 2). The next k lines each contain two integersa andb (1 ≤ a, b m), indicating beads of kinda cannot be stringed to beads of kindb.

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

像这种难度的估计也会看不到的,大牛们说随着polya置换知识为大家所普及,将来的polya题将是综合大题,估计我等小菜难以做出。

现在说此题:

此题大意很明确,就是求polya数,只不过有个让人头疼的限制条件就是给定一组数,告诉你他们是不能相邻的,现在问仍让你求出所有的数目,总之,看到此题

我是一点思路都没有的。不能相邻这个问题因该早已经解决了。到底用什么方法呢?我现在只能说是大概理解他的意思了。

利用神奇的矩阵来解决,实际上对于m种颜色,我们可以构造m*m的矩阵A,所有的元素都是1,你会发现A的一次是自己,二次方A^2的所有元素就是m^2,如此数学归纳可以很容得出结论:

A^n的所有元素均为m^(n-1),那么再观察以下就会发现,如果把对角线上的元素全部加起来的话,正好是m, A^n的对角线元素全加起来,正好是m^n次方。那么我们就可以猜测原来那个polya函数的公式:m^x因该是一个m*m矩阵A^x对角线上元素的和。现在有些元素元素不能相邻比如:x,y不能相邻,那么我们如何解决呢?大神们告诉我们的是:

A[x][y]=0,A[y][x]=0。然后在按上面的思路求即可。最终的结果是对于修改后的A,设A^n次方对角线上元素和为:tol,结果为:m^tol。好神奇!!!!

下面是我自己的代码,在POJ上交一直TLE,最后才发现原来是long long超的时,以后注意点,long long超时就该int,还要注意:MOD也很费时间,尽量少

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL int
const LL MOD = 9973;
const int N = 11;
LL n, k;

struct MAT {
    LL mat[N][N];
};

MAT operator*(MAT a, MAT b) {
    MAT c;
    memset(c.mat, 0, sizeof (c.mat));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < n; k++) {
                c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % MOD;
            }
        }
    }
    return c;
}

MAT operator^(MAT a, LL p) {
    MAT c;
    memset(c.mat, 0, sizeof (c.mat));
    for (int i = 0; i < n; i++) c.mat[i][i] = 1;

    MAT temp = a;
    while (p) {
        if (p & 1) {
            c = c*temp;
        }
        temp = temp*temp;
        p >>= 1;
    }
    return c;
}


MAT CT;

const int MAX = 41;
LL m;
LL res;
LL a[MAX];
int sizea[MAX];
int size;

LL quick(LL base, int p) {
    LL result = 1;
    base %= MOD;
    while (p) {
        if (p & 1) {
            result *= base;
            result %= MOD;
        }
        base *= base;
        base %= MOD;
        p >>= 1;
    }
    return result % MOD;
}

LL phi(LL num) {
    for (int i = 0; i < size; i++) {
        if (sizea[i] > 0) {
            num /= a[i];
            num *= (a[i] - 1);
        }
    }
    return num;
}

void DFS(int depth, LL num) {
    if (depth >= size) {
        MAT temp = CT^(num);
        int temp1 = 0;
        for (int i = 0; i < n; i++) {
            temp1 += temp.mat[i][i];
            temp1 %= MOD;
        }
        res = (res + temp1 * ((phi(m / num) % MOD)) % MOD) % MOD;
        return;
    }
    DFS(depth + 1, num);
    int temp2 = sizea[depth];
    while (sizea[depth]) {
        sizea[depth]--;
        num *= a[depth];
        DFS(depth + 1, num);
    }
    sizea[depth] = temp2;
}

int main() {
    int T;
    scanf("%d", &T);
    for (int p = 0; p < T; p++) {
        scanf("%d%d%d", &m, &n, &k);

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                CT.mat[i][j] = 1;
            }
        }

        int x, y;
        for (int i = 0; i < k; i++) {
            scanf("%d%d", &x, &y);
            CT.mat[x - 1][y - 1] = 0;
            CT.mat[y - 1][x - 1] = 0;
        }


        size = 0;
        LL temp = m;
        for (int i = 2; i * i <= temp; i++) {/*当temp达到int上界2147483647时,i*i会越界成为负值*/
            if (temp % i == 0) {
                sizea[size] = 0;
                a[size] = int(i);
                while (temp % i == 0) {
                    temp /= i;
                    sizea[size]++;
                }
                size++;
            }
        }
        
        if (temp > 1) {
            sizea[size] = 1;
            a[size] = temp;
            size++;
        }

        res = 0;
        DFS(0, 1);
        res = res * quick(m, MOD - 2) % MOD;
        printf("%d\n", res);
    }

    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值