日常訓練 20170606 魔法手鐲

題目描述

Ginny 的生日馬上就來了。魔法大叔 Herry 準備給他的新妹子一個生日禮物。禮物是由 N 個魔法珠子串成的魔法手鐲。每種不同種類的珠子有其獨一無二的特性。Herry 的另一個妹子遠阪凜指出,有一些指定種類的成對珠子,如果挨在一塊會發生化學反應甚至核聚變,因此 Herry 必須非常小心以確保這些珠子不會相鄰。

Herry想知道,究竟能有多少不同的手鐲,將這個結果 mod 9973 並告訴他。注意,若一個手鐲能夠通過旋轉得到另一個手鐲,我們將這兩個手鐲視爲相同的。

輸入格式

輸入包含多組數據。第一行一個正整數 case ,爲數據的組數。

接下來的數據分爲 case 組,每一組的第一行爲三個正整數 N,M,KN 爲珠子的數量,M 爲珠子的種類數,K 爲不能相鄰的種類對數,保證 N0 (mod 9973)

接下來 K 行每行兩個正整數 i,j ,表示種類 i 的珠子不能和種類 j 的珠子相鄰。

1case10 , 1N109 , 1M10

Burnside引理裸題,另外要求滿足一定限定條件的 n 個珠子有多少種方案,f[i][j] 表示第一個放 i 當前這個放 j 的方案數, dp轉移用矩陣乘法加速一下即可。

#include<bits/stdc++.h>
typedef long long ll;
const int P = 9973;
int Case, n, m, k, u, v, d[(int)1e5];
struct matrix{
    int a[11][11];
};
matrix e, full;
matrix operator * (const matrix &a, const matrix &b) {
    matrix c;
    memset(&c, 0, sizeof(c));
    for (int i=1; i <= m; i++)
        for (int j=1; j <= m; j++) {
            for (int k=1; k <= m; k++)
                c.a[i][j] += a.a[i][k] * b.a[k][j];
            c.a[i][j] %= P;
        }
    return c;
}
matrix pow(matrix x, int k) {
    matrix ret = e;
    for (; k; k >>= 1, x = x * x)
        if (k & 1) ret = ret * x;
    return ret;
}
int phi(int x) {
    int ret = x;
    for (int i=2; i * i <= x; i++)
        if (x % i == 0) {
            ret = ret / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    if (x > 1) ret = ret / x * (x - 1);
    return ret;
}
ll pow(ll x, int k) {
    ll ret = 1;
    for (; k; k >>= 1, x = x * x % P)
        if (k & 1) ret = ret * x % P;
    return ret;
}
ll inv (ll x) {return pow(x, P - 2);}
int main() {
    scanf("%d", &Case);
    for (int i=1; i <= 10; i++)
        e.a[i][i] = 1;
    for (int i=1; i <= 10; i++)
        for (int j=1; j <= 10; j++)
            full.a[i][j] = 1;
    while (Case--) {
        scanf("%d%d%d", &n, &m, &k);
        matrix tra = full;
        while (k--)
            scanf("%d%d", &u, &v),
            tra.a[u][v] = 0,
            tra.a[v][u] = 0;
        matrix cp = tra;
        ll ans = 0;
        int kind = 0;
        for (int i=1; i * i <= n; i++)
            if (n % i == 0)
                d[++kind] = i,
                d[++kind] = n / i;
        if (kind >= 2 && d[kind] == d[kind - 1]) kind--;
        for (int k=1; k <= kind; k++)
            if (n % d[k] == 0) {
                matrix f = e * pow(tra, n / d[k] - 1);
                ll tans = 0;
                for (int i=1; i <= m; i++)
                    for (int j=1; j <= m; j++)
                        if (cp.a[i][j]) tans += f.a[i][j];
                ans = (ans + tans * phi(d[k]));
            }
        printf("%lld\n", ans * inv(n) % P);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章