poj2154Color Polya定理+欧拉函数
Posted GXZlegend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj2154Color Polya定理+欧拉函数相关的知识,希望对你有一定的参考价值。
$T$ 组询问,用 $n$ 种颜色去染 $n$ 个点的环,旋转后相同视为同构。求不同构的环的个数模 $p$ 的结果。 $T\\le 3500,n\\le 10^9,p\\le 30000$ 。
题解
Polya定理+欧拉函数
根据 poj2409 中得到的结论,答案为:
$\\frac{\\sum\\limits_{i=1}^nn^{\\gcd(i,n)}}n=\\sum\\limits_{i=1}^nn^{\\gcd(i,n)-1}$
由于 $n$ 有 $10^9$ 之大,因此考虑优化这个式子。
枚举 $\\gcd(i,n)$ ,则有:
$Ans=\\sum\\limits_{d|n}n^{d-1}\\sum\\limits_{j=1}^{\\frac nd}[\\gcd(j·d,n)==d]\\\\\\ \\ \\ \\ \\ \\ \\ =\\sum\\limits_{d|n}n^{d-1}\\sum\\limits_{j=1}^{\\frac nd}[\\gcd(j,\\frac nd)==1]\\\\\\ \\ \\ \\ \\ \\ \\ =\\sum\\limits_{d|n}n^{d-1}\\varphi(\\frac nd)\\\\\\ \\ \\ \\ \\ \\ \\ =\\sum\\limits_{k|n}n^{\\frac nk-1}\\varphi(k)$
此时 $k$ 是 $n$ 的约数,总个数不会超过 $O(\\sqrt n)$ 个。但是直接枚举约数的话难以快速算出 $\\varphi$ 值。
考虑将 $n$ 分解质因数,设 $n=\\prod\\limits_{i=1}^mp_i^{a_i}$ ,那么我们dfs枚举 $k=\\prod\\limits_{i=1}^mp_i^{b_i}\\ (0\\le b_i\\le a_i)$ ,由于 $\\varphi$ 是积性函数,所以在枚举的过程中就可以顺便求出 $\\varphi$ 值 ,再与 $n^{\\frac nk-1}$ 作乘积累加到答案中即可。这样能够不重不漏地枚举到 $n$ 的所有约数并统计答案。
时间复杂度 $O(T\\sqrt n\\log n)$ ,由于这个根号是远远不满的,因此可以过。
#include <cstdio> int a[40] , c[40] , tot , n , p , ans; inline int pow(int x , int y) { int ans = 1; while(y) { if(y & 1) ans = ans * x % p; x = x * x % p , y >>= 1; } return ans; } void dfs(int x , int d , int v) { if(x > tot) { ans = (ans + pow(n % p , n / d - 1) * (v % p)) % p; return; } int i; dfs(x + 1 , d , v); d *= a[x] , v *= a[x] - 1; for(i = 1 ; i <= c[x] ; i ++ , d *= a[x] , v *= a[x]) dfs(x + 1 , d , v); } int main() { int T , i , x; scanf("%d" , &T); while(T -- ) { scanf("%d%d" , &n , &p); tot = 0 , x = n; for(i = 2 ; i * i <= x ; i ++ ) { if(!(x % i)) { a[++tot] = i , c[tot] = 0; while(!(x % i)) x /= i , c[tot] ++ ; } } if(x != 1) a[++tot] = x , c[tot] = 1; ans = 0 , dfs(1 , 1 , 1); printf("%d\\n" , ans); } return 0; }
以上是关于poj2154Color Polya定理+欧拉函数的主要内容,如果未能解决你的问题,请参考以下文章
Polya定理枚举约数欧拉函数Javapoj2154 Color