洛谷P4607 [SDOI2018] 反回文串
设长度为 \(n\) 字符集大小为 \(k\) 的回文串的个数为 \(g(n)=k^{\left\lceil\frac{n}{2}\right\rceil}\),回文串的每个循环位移都有贡献,但因为循环同构,直接算会算重。不难发现若一个回文串是由同一个串重复循环得到的,那么该串也为回文串,即若有回文串 \(s=t^k\),则 \(t\) 也为回文串。考虑枚举回文串的最小循环串长度。
设 \(v(n)\) 为一个回文串的最小循环串长度为 \(n\) 时的贡献,\(n\) 为偶数时会计算两遍,因为当回文串循环位移了 \(\frac{n}{2}\) 后,又会得到一个最小循环串长度为 \(n\) 的回文串,因此得 \(v(n)=n\frac{1+\left[ 2 \not\mid n \right]}{2}\)。
设 \(f(n)\) 为最小循环串为其本身的长度为 \(n\) 的回文串个数,得:
得答案为:
考虑进一步化简 \(\sum\limits_{d\mid \frac{n}{t}}\mu\left(d\right)v(dt)\),发现除了 \(d\) 为偶数且 \(t\) 为奇数的情况,都有 \(v(dt)= dv(t)\)。考虑 \(d\) 为偶数且 \(t\) 为奇数时一定有 \(\frac{n}{t}\) 也为偶数,于是可以将满足 \(\mu(d)\neq 0\) 且 \(d\) 中质因子没有 \(2\) 的 \(d\) 和 \(2d\) 进行配对,因为此时有 \(v(dt)=dt=v(2dt)\),所以两两配对后得 \(\sum\limits_{d\mid \frac{n}{t}}\mu\left(d\right)v(dt)=0\)。
于是就可以代入 \(v(dt)= dv(t)\),得答案为:
用 \(Pollard-Rho\) 将 \(n\) 质因数分解后,用 \(dfs\) 枚举 \(n\) 的约数,\(dfs\) 过程中维护 \(\prod\limits_{p\mid \frac{n}{t}}\left( 1-p \right)\) 即可。
#include<bits/stdc++.h>
#define maxn 110
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
ll T,n,k,p,cnt,tot,ans;
ll pri[12]={2,3,5,7,11,13,17,19},t[maxn],v[maxn],a[maxn];
ll mul(ll x,ll y,ll mod)
{
ll c=(long double)x*y/mod+0.5;
c=x*y-c*mod;
return c<0?c+mod:c;
}
ll qp(ll x,ll y,ll mod)
{
ll v=1;
while(y)
{
if(y&1) v=mul(v,x,mod);
x=mul(x,x,mod),y>>=1;
}
return v%mod;
}
bool check(ll x,ll p,ll mod)
{
ll t=qp(x,p,mod);
if(t==mod-1) return true;
if(t==1) return p&1?true:check(x,p/2,mod);
return false;
}
bool Miller_Rabin(ll n)
{
if(n==1) return false;
if(n<=3) return true;
if(!(n&1)) false;
for(int i=0;i<8;++i)
{
if(n==pri[i]) return true;
if(!check(pri[i],n-1,n)) return false;
}
return true;
}
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll f(ll x,ll y,ll mod)
{
return (mul(x,x,mod)+y)%mod;
}
ll Pollard_Rho(ll x)
{
ll s=0,t=0,c=(ll)rand()%(x-1)+1,val=1;
for(ll goal=1;;goal<<=1,s=t,val=1)
{
for(ll step=1;step<=goal;++step)
{
t=f(t,c,x);
val=mul(val,abs(t-s),x);
if(step%127==0)
{
ll d=gcd(val,x);
if(d>1) return d;
}
}
ll d=gcd(val,x);
if(d>1) return d;
}
}
void fac(ll x)
{
if(x<2) return;
if(Miller_Rabin(x))
{
t[++cnt]=x;
return;
}
ll p=x;
while(p>=x) p=Pollard_Rho(x);
fac(x/p),fac(p);
}
void dfs(int x,ll d,ll t)
{
if(x==tot+1)
{
if(!(n/d&1)||(d&1))
ans=(ans+qp(k,(n/d+1)/2,p)*(((n/d&1)?n/d:n/d/2)%p)%p*t%p)%p;
return;
}
dfs(x+1,d,t),t=t*(1-v[x]%p+p)%p;
for(int i=1;i<=a[x];++i) d*=v[x],dfs(x+1,d,t);
}
int main()
{
srand((ll)new char),read(T);
while(T--)
{
read(n),read(k),read(p),k%=p,cnt=tot=ans=0;
fac(n),sort(t+1,t+cnt+1);
for(int i=1;i<=cnt;++i)
{
if(t[i]!=t[i-1]) v[++tot]=t[i],a[tot]=0;
a[tot]++;
}
dfs(1,1,1),printf("%lld\n",ans);
}
return 0;
}