题目链接:
POJ 2888 Magic Bracelet
题意:
有一串 n 个珠子的项链,用
分析:
因为需要考虑旋转,所以很容易想到 Polya计数和Burnside引理。
假设有 k 个循环,用
用 dp[k][i][j] 表示经过 k 个循环从第
初始化: dp[1][i][j]=1?link[i][j]
初始矩阵: A[i][j]=1?link[i][j] 来表示颜色间的连通性
由上面的递推式, Ak[i][j] 代表的是:从第 i 种颜色经过
离散数学里有:如果用0,1矩阵A来表示无向图的连通情况的话,A^k代表的就是一个点经过k条路后能到达的地方的方法数。
假设对于每个循环的步长为 i ,也就是
满足循环个数为 k 的置换的旋转步长
综上对于每个满足 n%k=0 的 k 可以得到的方案数是
枚举每个 k 然后求和最后还要除以
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const ll mod = 9973;int link[15][15];struct Matrix{int row, col;ll data[15][15];Matrix operator * (const Matrix& rhs) const { //矩阵相乘条件:col = rhs.rowMatrix res;res.row = row, res.col = rhs.col;for(int i = 1; i <= res.row; ++i) {for(int j = 1; j <= res.col; ++j) {res.data[i][j] = 0;for(int k = 1; k <= row; ++k) {res.data[i][j] += data[i][k] * rhs.data[k][j];} res.data[i][j] %= mod;//要是写成: //res.data[i][j] = (res.data[i][j] + data[i][k] * rhs.data[k][j] % mod) % mod,//会TLE,辣鸡}}return res;}Matrix operator ^ (const int m) const { //矩阵快速幂Matrix res, tmp;res.row = row, res.col = col; //row == colmemset(res.data, 0, sizeof(res.data));tmp.row = row, tmp.col = col;memcpy(tmp.data, data, sizeof(data));for(int i = 1; i <= res.row; ++i) { res.data[i][i] = 1; }int mm = m;while(mm) {if(mm & 1) res = res * tmp;tmp = tmp * tmp;mm >>= 1;}return res;}
};inline ll quick_pow(ll a, ll b, ll p)
{ll res = 1, tmp = a;while(b) {if(b & 1) res = res * tmp % p;tmp = tmp * tmp % p;b >>= 1;}return res;
}inline ll phi(int x)
{ll res = x;for(int i = 2; i * i <= x; ++i) {if(x % i == 0) {res = res / i * (i - 1);while(x % i == 0) { x /= i; }}}if(x > 1) res = res / x * (x - 1);return res;
}inline ll solve(int len, int m)
{Matrix tmp;tmp.row = tmp.col = m;for(int i = 1; i <= m; ++i) {for (int j = 1; j <= m; ++j) {tmp.data[i][j] = 1 - link[i][j];}}tmp = tmp ^ len;ll ans = 0;for (int i = 1; i <= m; ++i) {ans = (ans + tmp.data[i][i]) % mod;}return ans;
}int main()
{int T, n, m, t;scanf("%d", &T);while (T--) {memset(link, 0, sizeof(link));scanf("%d%d%d", &n, &m, &t);for(int i = 0; i < t; ++i) {int former, later;scanf("%d%d", &former, &later);link[former][later] = link[later][former] = 1;}ll ans = 0;for(int i = 1; i * i <= n; ++i) {if(n % i) continue;ans = (ans + phi(n / i) * solve(i, m)) % mod;if(n / i == i) continue;ans = (ans + phi(i) * solve(n / i, m)) % mod;}printf("%lld\n", ans * quick_pow(n % mod, mod - 2, mod) % mod);}return 0;
}