码迷,mamicode.com
首页 > 其他好文 > 详细

P4980 【模板】Polya定理

时间:2019-02-10 17:38:50      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:置换   mod   work   数据   ide   long   getchar   ret   颜色   

\(\color{#0066ff}{ 题目描述 }\)

给定一个\(n\)个点,\(n\)条边的环,有\(n\)种颜色,给每个顶点染色,问有多少种本质不同的染色方案,答案对\(10^9+7\)取模

注意本题的本质不同,定义为:只需要不能通过旋转与别的染色方案相同

\(\color{#0066ff}{输入格式}\)

第一行输入一个\(t\),表示有\(t\)组数据

第二行开始,一共\(t\)行,每行一个整数\(n\),意思如题所示。

\(\color{#0066ff}{输出格式}\)

\(t\)行,每行一个数字,表示染色方案数对\(10^9+7\)取模后的结果

\(\color{#0066ff}{输入样例}\)

5
1 
2 
3 
4 
5 

\(\color{#0066ff}{输出样例}\)

1
3
11
70
629

\(\color{#0066ff}{数据范围与提示}\)

\(n \leq 10^9\)\(,t \leq 10^3\)

\(\color{#0066ff}{ 题解 }\)

前置知识

1、置换

就是将元素的对应以表格形式来表示

标准形式为

\(\left(\begin{aligned}1 && 2 && 3 && 4 && \dots && n \\ \ a_1 && a_2 && a_3 && a_4 && \dots && a_n\end{aligned}\right)\)

其中\(a_1\dots a_n\)\(1-n\)的一个排列

相当于经过变换,原来1的位置到了\(a_1\),2的位置到了\(a_2\)。。。

根据题意,本质不同即为旋转

于是单次置换为

\(\left(\begin{aligned}1 && 2 && 3 && 4 && \dots && n \\ \ 2 && 3 && 4 && 5 && \dots && 1\end{aligned}\right)\)

二次置换为

\(\left(\begin{aligned}1 && 2 && 3 && 4 && \dots && n \\ \ 3 && 4 && 5 && 6 && \dots && 2\end{aligned}\right)\)

2、Burnside引理

对于每个置换f,我们定义C(f)为在置换f下保持不变的方案数。

则有: 本质不同的方案数为C(f)的平均数。

\(ans=\frac{1}{\left | G \right |} \sum _{f \in G}\)

3、Polya定理

\(\begin{aligned}ans=\frac 1 n \sum_{i=1}^n m^{x_i}\end{aligned}\)

其中,n为置换长度,m是染色种类,\(x_i\)是i次置换的循环个数

循环个数是啥呢

比如上面的一次置换,个数为1,\(1\to2\to3\to4\to5\to1\)

比如长度为6的三次置换,个数为3

\(\left(\begin{aligned}1 && 2 && 3 && 4 && 5 && 6\\ 4 && 5 && 6 && 1 && 2 && 3\end{aligned}\right)\)

第一个循环\(1\to4\to1\)

第二个循环\(2\to5\to2\)

第三个循环\(3\to6\to3\)

不难发现,\(x_i=gcd(i,n)\)

于是改为枚举n的因子

\(\begin{aligned}ans=\frac 1 n \sum_{i=1}^n m^{gcd(i,n)}\end{aligned}\)

\(\begin{aligned}ans=\frac 1 n \sum_{d|n}^n \varphi(\frac n d)* m^{d}\end{aligned}\)

表面上这东西的复杂度是\(O(T*(\sqrt n)^2)=O(Tn)\)

但实际上,求\(\varphi\)的根号只会被调用log次

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int mod = 1e9 + 7;
LL ksm(LL x, LL y) {
    LL re = 1LL;
    while(y) {
        if(y & 1) re = re * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return re;
}
LL getphi(LL n) {
    LL ans = n;
    for(LL i = 2; i * i <= n; i++) {
        if(n % i == 0) {
            ans = ans / i * (i - 1);
            while(n % i == 0) n /= i;
        }
    }
    if(n != 1) ans = ans / n * (n - 1);
    return ans;
}

LL work(LL n) {
    LL ans = 0;
    for(LL i = 1; i * i <= n; i++) {
        if(n % i == 0) {
            (ans += ksm(n, i) * getphi(n / i) % mod) %= mod;
            if(i * i != n) (ans += ksm(n, n / i) * getphi(i) % mod) %= mod;
        }
    }
    return ans * ksm(n, mod - 2) % mod;
}

int main() {
    for(int T = in(); T --> 0;) printf("%lld\n", work(in()));
    return 0;
}

P4980 【模板】Polya定理

标签:置换   mod   work   数据   ide   long   getchar   ret   颜色   

原文地址:https://www.cnblogs.com/olinr/p/10359459.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!