链接:Orz
题意:n 个珠子,有 k 种颜色,问:有多少种方法本质不一样的方法填色 (旋转几个相同就是一样的)
题解:poyla定理吧,百度百科上有图:
关于图里面的一些解释
(置换群,你就看成有 n 个成员的一个环啥的 !?)
1.置换,首先要知道置换是个什么东西
上面这个 1 2 3 4 5
到下面这 a1 a2 a3 a4 a5 的映射算一种置换
( 像正方形旋转那种,也可以看成顶点的置换 )
2. 循环节数,在一个置换中,有几个循环,像是 1 2 3 4 , { 1,3 },{ 2, 4}可以互到达的有 2 个,所以循环节数为 2
3 4 1 2
3. p1,p2,.....,pk ,就是每一步走的步数 ( 一下走 1 步,一下走 2 步什么?)
那么上面那个式子变成了 L = 1 / 步数种数 * (∑ m ^ (每种步数构成的循环节数))
怎么求这个循环节数呢 {
每次走 i 步, 走回原来的位置 , 需要的次数 cnt 是:每次走 i 步的这样的走 lcm(i, n) / i步数
那么在这 cnt 次的走动中,每个踩到的值可以拿出来成一个循环
比如 1 2 3 4 { 1, 3 } { 2 , 4 }就是可以拿出来,那么这个置换存在 2 个循环节数
3 4 1 2
一共可以走 1 步到走 n 步,他们的循环节数就是 n / cnt ,(cnt 一个循环,n / cnt 个循环节数)
}
那么 ans = 1/n * ∑ (m ^ (n/cnt))
cnt = lcm(i,n) / i , n / lcm( i , n) / i === n * i / lcm (i,n) === gcd(i,n)
那么 ans = 1/n * ∑ (m ^ (gcd(i,n)))
所以有代码:
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
#define rep(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
long long gcd(ll a,ll b) {
return b ? gcd(b,a%b) : a;
}
long long bigmod(ll a,ll b) {
ll res = 1;
while(b) {
if(b&1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
int main() {
int T;
scanf("%d",&T);
rep(t,1,T) {
int n,k;
long long sum = 0;
scanf("%d %d",&n,&k);
rep(i,1,n) {
sum = (sum + bigmod(k,gcd(i,n))) % mod;
}
sum = sum * bigmod(n,mod-2) % mod;
printf("Case %d: %lld\n",t,sum);
}
}
/*
∑quick(k,gcd(i,n))
---------------------
n
*/
最后呢 , poyla 有很多题不只是这一种形式 , 比如翻转什么的 !? HDU --- 3923 Invoker 这个题就包含了翻转,可以试着写一写