链接: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
#include
#include
#include
#include
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;
}