链接:https://www.lydsy.com/JudgeOnline/problem.php?id=5330
难题做不来。。跑了跑了
如果按照loj的数据范围,我已经爆0了
首先,朴素的想法就是暴力控制
n
/
2
n/2
n/2位,然后乘个n
但是你会发现,会有很多重复
考虑怎么样不会有重复,我们对于每个串,不要加上n
我们加上一个数
x
x
x,
x
x
x是这个回文串在将前缀x个位丢到后面会变成回文串
容易发现,这样就没有重复了
考虑一个东西的
x
x
x怎么算
猜了很多个与gcd有关的结论。。都被
A
B
B
A
A
B
B
A
ABBAABBA
ABBAABBA搞自闭了。。
但其实这个结论并不和gcd有关。。于是我就爆0了
我们先找他的循环节,设其长度为
l
e
n
len
len,如果
l
e
n
len
len为偶数,那么
x
x
x就是
l
e
n
/
2
len/2
len/2,否则就是
l
e
n
len
len,(这个结论怎么证呢?T_T)
我们设
l
e
n
len
len和
x
x
x的转化关系为
h
(
l
e
n
)
h(len)
h(len)
解决了这个,那么每个串的贡献就之和他的循环节有关了
设
f
(
i
)
f(i)
f(i)表示循环节为
i
i
i的回文串有多少个,
g
(
n
)
g(n)
g(n)表示长度为n的回文串
不难得到
∑
d
∣
n
f
(
n
)
=
g
(
n
)
\sum_{d|n}f(n)=g(n)
d∣n∑f(n)=g(n)
又是熟悉的配方反演一下可以得到
f
(
n
)
=
∑
d
∣
n
μ
(
n
d
)
g
(
d
)
f(n)=\sum_{d|n}\mu(\frac{n}{d})g(d)
f(n)=d∣n∑μ(dn)g(d)
根据定义可以得到
a
n
s
=
∑
d
∣
n
f
(
d
)
∗
h
(
d
)
ans=\sum_{d|n}f(d)*h(d)
ans=d∣n∑f(d)∗h(d)
暴力把二式套进去,可以得到
a
n
s
=
∑
d
∣
n
h
(
d
)
∑
k
∣
d
g
(
k
)
μ
(
d
k
)
ans=\sum_{d|n}h(d)\sum_{k|d}g(k)\mu(\frac{d}{k})
ans=d∣n∑h(d)k∣d∑g(k)μ(kd)
按照化式子的套路,我们把k提到前面枚举
a
n
s
=
∑
k
∣
n
g
(
k
)
∑
d
∣
n
k
h
(
d
k
)
μ
(
d
)
ans=\sum_{k|n}g(k)\sum_{d|\frac{n}{k}}h(dk)\mu(d)
ans=k∣n∑g(k)d∣kn∑h(dk)μ(d)
然后陷入僵局。。
根据题解,我们尝试发现一些规律
首先,看一下这个
h
(
d
k
)
h(dk)
h(dk)能不能变成
d
∗
h
(
k
)
d*h(k)
d∗h(k)
如果可以的话,那么式子的前后就变得很可做的样子
发现,
h
(
d
k
)
≠
d
∗
h
(
k
)
h(dk)≠d*h(k)
h(dk)̸=d∗h(k)的情况,当且仅当
d
k
dk
dk为偶数,且
k
k
k为奇数
我们再来观察一下当满足这些条件的时候
∑
d
∣
n
k
h
(
d
k
)
μ
(
d
)
\sum_{d|\frac{n}{k}}h(dk)\mu(d)
d∣kn∑h(dk)μ(d)会变成什么
因为k是奇数,所以可以得到d是一个偶数,所以
n
k
\frac{n}{k}
kn也是偶数
根据题解我们不妨直接讨论一个更大的范围,就是讨论
k
k
k为奇数
n
k
\frac{n}{k}
kn为偶数的情况
要注意,这里对dk并没有要求,我们讨论了一个更大的范围
我们发现,假如我们只考虑
μ
\mu
μ不为0的情况
d
d
d含
2
2
2和不含
2
2
2的情况,刚好
μ
\mu
μ为相反数,且
h
(
d
k
)
h(dk)
h(dk)是一样的!
因此,我们可以跳过所有
k
k
k为奇数
n
k
\frac{n}{k}
kn为偶数的情况,那么,
h
(
d
k
)
h(dk)
h(dk)就可以提出来了
最后,式子变成了
a
n
s
=
∑
k
∣
n
g
(
k
)
h
(
k
)
∑
d
∣
n
k
d
μ
(
d
)
ans=\sum_{k|n}g(k)h(k)\sum_{d|\frac{n}{k}}d\mu(d)
ans=k∣n∑g(k)h(k)d∣kn∑dμ(d)
最后一步,考虑后面的是什么。依然考虑 μ \mu μ有值的情况,容易发现,这个东西就是 Π ( 1 − p i ) \Pi(1-p_i) Π(1−pi),其中 p i p_i pi是 n k \frac{n}{k} kn的质因数
于是问题就解决了,用rho来分解找因数即可
终于写完了
感觉这题还是很有启发的啊
1.猜循环节有关的结论不要死在gcd里面,有时暴力+1,-1,/2,*2可能会有奇效
2.一些式子看起来不好搞的时候,试一下可不可以换掉,换成一些可以求的。比如说这里的莫比乌斯反演
3.化
μ
\mu
μ的时候还是要记住考虑
μ
\mu
μ不为0的情况
4.有时候观察一下不可以化简的部分是否可以忽略掉
顺便学了一发更快的rho
有个细节就是最后dfs的时候快速幂没有必要用快速乘,只有rho的时候才要,否则你会T飞
但其实并没有关系,因为我也不会做
最后是CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
const LL N=105;
LL T;
LL pri[14]={0,2,3,5,7,11,13,17,19,23,29,31,37,41};
LL gcd (LL x,LL y) {return x==0?y:gcd(y%x,x);}
LL mul (LL x,LL y,LL MOD)
{
x%=MOD;
LL lalal=0;
while (y>0)
{
if (y&1) lalal=(lalal+x)%MOD;
x=x+x;if (x>=MOD) x-=MOD;
y>>=1;
}
return lalal;
}
LL Pow (LL x,LL y,LL MOD)
{
x%=MOD;
LL lalal=1;
while (y>0)
{
if (y&1) lalal=mul(lalal,x,MOD);
x=mul(x,x,MOD);y>>=1;
}
return lalal;
}
vector<LL> vec;
bool check (LL p)
{
for (LL u=1;u<=13;u++)
{
if (p==pri[u]) return true;
if (p%pri[u]==0) return false;
}
LL k=0,t=p-1;
while (t%2==0) {t>>=1;k++;}
for (LL u=1;u<=13;u++)
{
LL x=Pow(pri[u],t,p);
for (LL i=0;i<k;i++)
{
LL y=mul(x,x,p);
if (y==1&&x!=1&&x!=p-1) return false;
x=y;
}
if (x!=1) return false;
}
return true;
}
LL rho (LL n)
{
LL c=rand()%(n-1)+1,x=rand()%n,y=x,p=1,k=1;
for (LL u=1;p==1;u++)
{
x=(mul(x,x,n)+c)%n;
if (x==y) return n;
p=gcd(n,x>y?x-y:y-x);
if (u==k) {y=x;k<<=1;}
}
return p;
}
void div (LL n)
{
if (n==1) return ;
if (check(n)) {vec.push_back(n);return ;}
LL p=1;
while (p==1) p=rho(n);
div(p);div(n/p);
}
LL n,k,MOD;
LL a[N];
int b[N];
int tot;
LL ans;
LL H (LL x) {return x&1?x%MOD:(x>>1)%MOD;}
LL Pow1 (LL x,LL y)
{
x%=MOD;
LL lalal=1;
while (y>0)
{
if (y&1) lalal=lalal*x%MOD;
x=x*x%MOD;y>>=1;
}
return lalal;
}
void dfs (int now,LL d,LL xx)
{
if (now>tot)
{
LL nn=n/d;
if (!(d&1)&&((nn)&1)) return ;
ans+=Pow1(k,(nn+1)>>1)*H(nn)%MOD*xx%MOD;
return ;
}
dfs(now+1,d,xx);
xx=xx*(1-a[now])%MOD;
for (int u=1;u<=b[now];u++) {d=d*a[now];dfs(now+1,d,xx);}
}
int main()
{
scanf("%lld",&T);
while (T--)
{
vec.clear();
scanf("%lld%lld%lld",&n,&k,&MOD);k%=MOD;
div(n);
sort(vec.begin(),vec.end());
int siz=vec.size();
tot=0;
for (int u=0;u<siz;u++)
{
if (tot==0||vec[u]!=a[tot]) {a[++tot]=vec[u];b[tot]=1;}
else b[tot]++;
}
ans=0;
dfs(1,1,1);
printf("%lld\n",(ans%MOD+MOD)%MOD);
}
return 0;
}