一、题目
题目描述
长度为 n n n的环 n n n染色,求旋转后本质不同的方案模 p p p的值。
数据范围
1 ≤ n ≤ 1 e 9 1\leq n\leq1e9 1≤n≤1e9, 1 ≤ p ≤ 30000 1\leq p\leq 30000 1≤p≤30000
二、解法
首先直接来推式子:
∑
i
=
1
n
n
gcd
(
i
,
n
)
\sum_{i=1}^nn^{\gcd(i,n)}
i=1∑nngcd(i,n)
∑
d
∣
n
n
d
∑
i
=
1
n
[
gcd
(
i
,
n
)
=
d
]
\sum_{d|n}n^d\sum_{i=1}^n[\gcd(i,n)=d]
d∣n∑ndi=1∑n[gcd(i,n)=d]
∑
d
∣
n
n
d
ϕ
(
n
d
)
\sum_{d|n}n^d\phi(\frac{n}{d})
d∣n∑ndϕ(dn)这道题不能线性筛预处理,所以只能在线求
ϕ
\phi
ϕ,单次时间复杂度比
O
(
n
)
O(n)
O(n)小,但是能过。注意本题不需要
l
o
n
g
l
o
n
g
long long
longlong,过程中注意模就可以了,贴个代码。
#include <cstdio>
const int M = 40005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,jzm,ans,cnt,p[M],vis[M];
void init(int n)
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) p[++cnt]=i;
for(int j=1;j<=cnt && i*p[j]<=n;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int phi(int n)
{
int r=n;
for(int i=1;p[i]*p[i]<=n;i++)
if(n%p[i]==0)
{
r=r/p[i]*(p[i]-1);
while(n%p[i]==0) n/=p[i];
}
if(n>1) r=r/n*(n-1);
return r%jzm;
}
int qkpow(int a,int b)
{
int r=1;a%=jzm;
while(b>0)
{
if(b&1) r=r*a%jzm;
a=a*a%jzm;
b>>=1;
}
return r;
}
signed main()
{
init(4e4);
T=read();
while(T--)
{
ans=0;
n=read();jzm=read();
for(int i=1;i*i<=n;i++)
if(n%i==0)
{
ans=(ans+phi(n/i)*qkpow(n,i-1))%jzm;
if(i*i!=n)
ans=(ans+phi(i)*qkpow(n,n/i-1))%jzm;
}
printf("%d\n",ans);
}
}