HDU 2865 Birthday Toy

\(HDU2865\ Birthday\ Toy\)

🔗

Polya计数的各种操作

这道题只有旋转,没有翻转,所以一共有\(n\)种置换,其中\(gcd\)相同的可以一起处理,这里可以用欧拉函数来进行优化。
对于\(gcd\)相同的一类旋转,首先考虑中间的颜色,可以取\(k\)种中的任意一种,然后剩下的任务就是用\(k-1\)种颜色涂到外层的\(n\)各点上,并且保证相邻的点颜色不同。现在要找不动元的数量,可以发现不动元的数量就是用\(k-1\)种颜色涂在大小为\(gcd\)的环上且相邻颜色不同的方案数。
现在来求这个方案数,设\(f[i]\)表示当前是环上第\(i\)个位置,且颜色和第一个一样的方案数,\(g[i]\)表示当前是环上第\(i\)个且颜色和第一个不同的方案数,状态转移为\(f[i]=g[i-1]\)\(g[i]=f[i-1]\cdot (k-2) + g[i-1] \cdot (k-3)\),其中\(f[1]=k-1\)\(g[1]=0\)(第一个位置能涂任何颜色,显然自己和自己只能颜色相同)由于数据量比较大,所以用矩阵快速幂来优化它

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
const LL MOD = 1e9+7;
LL n,m;
struct Matrix{
    LL mat[2][2];
    Matrix(int tag = 1){
        mat[0][0] = mat[1][1] = tag;
        mat[0][1] = mat[1][0] = 0;
    }
    Matrix operator * (const Matrix rhs){
        Matrix ret(0);
        for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++){
            for(int k = 0; k < 2; k++) ret.mat[i][j] = (ret.mat[i][j]+mat[i][k]*rhs.mat[k][j])%MOD;
        }
        return ret;
    }
};
Matrix Matrixqpow(Matrix M, LL b){
    Matrix ret(1);
    while(b){
        if(b&1) ret = ret * M;
        b >>= 1;
        M = M * M;
    }
    return ret;
}
LL phi(LL x){
    LL phi = x;
    for(int i = 2; i*i <= x; i++){
        if(x%i) continue;
        phi = phi / i * (i-1);
        while(x%i==0) x /= i;
        if(x==1) break;
    }
    if(x!=1) phi = phi / x * (x-1);
    return phi;
}
LL qpow(LL a, LL b){
    LL ret = 1;
    while(b){
        if(b&1) ret = ret * a % MOD;
        b >>= 1;
        a = a * a % MOD;
    }
    return ret;
}
vector<LL> calfact(LL x){
    vector<LL> vec;
    for(int i = 1; i * i <= x; i++){
        if(x%i) continue;
        vec.emplace_back(i);
        if(x/i!=i) vec.emplace_back(x/i);
    }
    return vec;
}
LL giao(LL x){
    Matrix M(0);
    M.mat[0][0] = 0; M.mat[1][0] = 1;
    M.mat[1][1] = m - 3; M.mat[0][1] = m - 2;
    M = Matrixqpow(M,x-1);
    return (m-1) * M.mat[0][1] % MOD;
}
void solve(){
    vector<LL> vec = calfact(n);
    LL ret = 0;
    for(LL g : vec) ret = (ret + phi(n/g) * m % MOD * giao(g) % MOD) % MOD;
    ret = ret * qpow(n,MOD-2) % MOD;
    cout << ret << endl;
}
int main(){
    ____();
    while(cin >> n >> m) solve();
    return 0;
}
posted @ 2020-03-22 21:59  _kiko  阅读(118)  评论(0编辑  收藏  举报