刚开始,没什么思路,后来才知道要用到polya定理,本来还以为是一道排列问题,最后却变成了一道群的轮换问题,最后由于数据非常大,又要mod除法运算,因此要求乘法逆元。
polya定理 参考:http://www.docin.com/p-43391964.html
http://www.cppblog.com/sdfond/archive/2010/02/06/107403.aspx
http://hi.baidu.com/lewutian/blog/item/c75dff06c4693f6a03088100.html
mod除法运算:http://wenku.baidu.com/view/6f2879cca1c7aa00b52acb5f.html
http://wenku.baidu.com/view/6f2879cca1c7aa00b52acb5f.html
#include<cstdio>
#include<cstring>
#include<cmath>
long long colorgcd[10005];
const int mod=1000000007;
int gcd(int a,int b){ return b?gcd(b,a%b):a;}
int Extended_Euclid(int x,int mod)
{
int X1=1,X2=0,X3 = mod;
int Y1=0,Y2=1,Y3 = x;
while(true)
{
if (Y3 == 0) return 0; //无逆元
if (Y3 == 1) return Y2; //Y2为逆元
int Q = X3 / Y3;
int T1 = X1 - Q*Y1, T2 = X2 - Q*Y2, T3 = X3 - Q*Y3;
X1 = Y1; X2 = Y2; X3 = Y3;
Y1 = T1; Y2 = T2; Y3 = T3;
}
}
long long polya(int color,int n)
{
int i;
long long sum=0;
colorgcd[0] = 1;
for(i=1;i<=n;i++)
colorgcd[i] = (colorgcd[i-1] * color) % mod;
for(i=1; i<=n; i++)//旋转
{
sum += colorgcd[gcd(i,n)];
sum %= mod;
}
if(n&1)//翻转
{
sum += n*colorgcd[n/2+1];
sum %= mod;
sum *= Extended_Euclid(2*n,mod);
sum %= mod;
}
else
{
sum += (n/2)*colorgcd[n/2];
sum %= mod;
sum += (n/2)*colorgcd[n/2+1];
sum %= mod;
sum *= Extended_Euclid(2*n,mod);
sum %= mod;
}
sum = (sum + mod) %mod;
return sum;
}
int main()
{
//freopen(“out.txt”,”w”,stdout);
int cas,icas=0;
scanf(“%d”,&cas);
while(cas–)
{
int color,num;
scanf(“%d%d”,&color,&num);
memset(colorgcd,0,sizeof(colorgcd));
printf(“Case #%d: %I64d\n”,++icas,polya(color,num));
}
return 0;
}