《ybtoj金牌导航》第八部分第五章例题1 彩色项链1

题目大意

n n n种颜色的珠子连接在一起形成一条由 n n n个珠子组成的圆形项链。你的工作是计算可以生产多少种不同的项链。一串项链可以不用上全部颜色的珠子。
两条项链相同,当且仅当两条项链旋转后能重合在一起,且对应珠子的颜色相同。
你需要将答案对一个给定的数字 p p p取模。
多组数据。
n<=1e9

思路

polya定理。
但n的范围过大,所以我们需要优化。
L = 1 n ∑ 0 < k < n n g c d ( k , n ) L={1\over n}\sum_{0<k<n}n^{gcd(k,n)} L=n10<k<nngcd(k,n)
     = 1 n ∑ d ∣ n n d ∑ 0 < k < n [ g c d ( k , n ) = d ] ~~~~={1\over n}\sum _{d|n} n^d\sum_{0<k<n}[gcd(k,n)=d]     =n1dnnd0<k<n[gcd(k,n)=d]
     = ∑ d ∣ n n d − 1 ∑ 0 < k < n [ g c d ( k / d , n / d ) = 1 ] ~~~~=\sum _{d|n} n^{d-1}\sum_{0<k<n}[gcd(k/d,n/d)=1]     =dnnd10<k<n[gcd(k/d,n/d)=1]
     = ∑ d ∣ n n d − 1 ∑ 0 < k < n / d [ g c d ( k , n / d ) = 1 ] ~~~~=\sum _{d|n} n^{d-1}\sum_{0<k<n/d}[gcd(k,n/d)=1]     =dnnd10<k<n/d[gcd(k,n/d)=1]
     = ∑ d ∣ n ϕ ( n / d ) n d − 1 ~~~~=\sum _{d|n} \phi(n/d) n^{d-1}     =dnϕ(n/d)nd1
那么就这样了
code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
//When I wrote this code,God and I unterstood what was I doing 
inline long long read()
{
    long long ret,c,f=1;
    while (((c=getchar())> '9'||c< '0')&&c!='-');
    if (c=='-') f=-1,ret=0;
    else ret=c-'0';
    while ((c=getchar())>='0'&&c<='9') ret=ret*10+(c^48);
    return ret*f;
}
long long n,m;
long long ksm(long long x,long long y)
{
	x%=m;
	long long ans=1;
	while (y)
	{
		if (y&1) ans=ans*x%m;
		x=x*x%m;
		y>>=1;
	}
	return ans;
}
long long a[360005],tot;
bool b[360005];
void prime(long long x)
{
	b[1]=1;
	for (long long i=2;i<=x;i++)
	{
		if (b[i]) continue;
		a[tot++]=i;
		for (long long j=i*i;j<=x;j+=i) b[j]=1;
	}
	return;
}
long long phi(long long x)
{
	long long ans=x;
	for (long long i=0;a[i]*a[i]<=x;i++)
	{
		if (x%a[i]==0)
		{
			ans=ans-ans/a[i];
			while (x%a[i]==0) x/=a[i];
		}
	}
	if (x>1) ans=ans-ans/x;
	return ans%m;
}
int main()
{
	long long t=read();
	prime(360000);
	while (t--)
	{
		long long ans=0;
		n=read(),m=read();
		for (long long i=1;i*i<=n;i++)
		{
			if (i*i==n)
			{
				ans=(ans+ksm(n,i-1)*phi(i)%m)%m;
			}
			else if (n%i==0)
			{
				ans=(ans+ksm(n,i-1)*phi(n/i)%m)%m;
				ans=(ans+ksm(n,n/i-1)*phi(i)%m)%m;
			}
		}
		cout<<ans%m<<endl;
	}
	return 0;
}
//Now,only God know
//但行好事,莫问前程 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值