机器人的项链
题目链接
题目大意
题目里面说的很清楚了。
这个项链有n个的珠子组成,珠子的类型有m种,请问能组成多少种不同类型的项链(若一个项链可以通过另一个项的链旋转得到,那么认为这两个项链为同一种项链)。
题解
很明显的对称性计数,首先确定是Polya。算出结果后,得到ans:
ans=1n∑k=1nmgcd(n,k)
但是单纯的Polya还不行,鉴于n很大,我们不能从1一直枚举到n去求gcd(n,k),好在gcd(n,k)只有可能是n的约数,所以我们可以把相同的gcd(n,k)放到一起算,于是我们设gcd(n,k)=i:
gcd(n,k)=i设k=cigcd(n,ci)=i同除i,得到gcd(ni,c)=1
可以看到,最后一个式子中c的个数就是相同gcd(n,k)的个数,而c又是 ϕ(n/i) 的值(欧拉函数),所以我们可以通过求欧拉函数来求相同的gcd个数。
综上,最终ans
ans=1n∑i |nmiϕ(ni)
对了,最后还有一点:本题9937并不是质数…最后除法求模的时候n和9937并不一定互质…所以,最终的ans老老实实从0开始推吧…..
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define MOD 9937
#define LL long long
using namespace std;
LL n,m,h=0;
LL p[600005];
bool vis[600005];
void setup()
{
memset(vis,0,sizeof(vis));
memset(p,0,sizeof(p));
h=0; p[h++]=2;
for (int i=2;i<=600000;i+=2) vis[i]=1;
for (int i=3;i<=600000;i+=2) if (!vis[i])
{
p[h++]=i;
for (int j=i;j<=600000;j+=i) vis[j]=1;
}
}
LL pow_mod(LL a,LL b)
{
LL ans=1;
while (b)
{
if (b&1) ans=(ans*a)%MOD;
b>>=1;
a=(a*a)%MOD;
}
return ans;
}
LL eular(LL n)
{
LL ans=n;
for (int i=0;p[i]*p[i]<=n;i++)
if (n%p[i]==0)
{
LL t=n/p[i];
ans=(ans/p[i])*(p[i]-1);
while (n%p[i]==0) n/=p[i];
}
if (n>1) ans=(ans/n)*(n-1);
return ans;
}
int main()
{
setup();
while(scanf("%I64d%I64d",&n,&m)!=EOF)
{
LL ans=0,ti=0,high=(LL) sqrt(n);
for (int i=1;i<=high;i++) if (n%i==0)
{
LL t=eular(n/i),oth=n/i;
ans=(ans+t*pow_mod(m,i))%MOD;
if (i!=oth)
{
t=eular(n/oth);
ans=(ans+t*pow_mod(m,oth))%MOD;
}
}
for (ti=0;ti<MOD;ti++) if (ans ==(ti*(n%MOD)%MOD)) break;
printf("%I64d\n",ti);
}
return 0;
}