Luogu P4607 [SDOI2018]反回文串

Link
一个字符串\(S\)的不同的轮换数为\(|\sigma(S)|\),其中\(\sigma\)表示最小循环节。
直接计算\(\sum|\sigma|\)会把长度为偶数的循环节算重,设\(f(d)=\sum\limits[|\sigma|=d]\),那么\(ans=\sum\limits_{d|n}\frac{f(d)d}{1+[2|d]}\)
\(g(n)\)表示长度为\(n\)的回文串的数量,那么\(g(n)=k^{\lfloor\frac n2\rfloor}\)
显然\(g=f\times I\),因此\(f=g\times\mu\),记\(h(d)=\frac d{1+[2|d]}\)那么

\[\begin{aligned} ans&=\sum\limits_{d|n}(h\cdot(\mu\times g))(d)\\ &=\sum\limits_{d|n}g(d)\sum\limits_{t|\frac nd}\mu(t)h(dt) \end{aligned} \]

\(2\nmid d\wedge2|t\)时,不难发现\(\sum\limits_{t|\frac nd}\mu(t)h(dt)=0\)
否则我们有\(h(dt)=th(d)\),因此

\[\begin{aligned} ans&=\sum\limits_{d|n}g(d)\sum\limits_{t|\frac nd}\mu(t)h(dt)\\ &=((g\cdot h)\times(\mu\cdot id)\times I)(n) \end{aligned} \]

考虑\(((\mu\cdot id)\times I)(n)\),若\(n=\prod p_i^{e_i}\),分析贡献不难发现\(((\mu\cdot id)\times I)(n)=\prod(1-p_i)\)
那么我们dfs枚举\(n\)的约数时维护\(((\mu\cdot id)\times I)(n)=\prod(1-p_i)\)就可以\(O(d(n)\log n)\)地计算\(((g\cdot h)\times(\mu\cdot id)\times I)(n)\)了。

#include<map>
#include<cctype>
#include<cstdio>
#include<random>
#include<algorithm>
using i64=long long;
int tot;i64 n,k,ans,P;
struct prime{i64 p;int e;}a[20];std::map<i64,int>cnt;
std::mt19937 rng(19260817);
i64 read(){i64 x=0;char c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void inc(i64&a,i64 b){a+=b-P,a+=a>>63&P;}
i64 mul(i64 a,i64 b,i64 p){return (__int128)a*b%p;}
i64 add(i64 a,i64 b,i64 p){return a+=b-p,a+=a>>63&p;}
i64 pow(i64 a,i64 b,i64 p){i64 r=1;for(;b;b>>=1,a=mul(a,a,p))if(b&1)r=mul(a,r,p);return r;}
int Judge(i64 x)
{
    static int p[7]={2,3,5,7,11,61,24151};
    for(int i=0;i<7;++i) if(x==p[i]) return 1; else if(!(x%p[i])||pow(p[i],x-1,x)!=1) return 0;
    i64 phi=x-1;while(~phi&1) phi>>=1;
    for(int i=0;i<7;++i)
    {
	i64 y=pow(p[i],phi,x);
	if(y==1) continue;
	while(y!=1&&y!=x-1) y=mul(y,y,x);
	if(y==1) return 0;
    }
    return 1;
}
i64 Find(i64 x)
{
    i64 c=rng()%(x-1)+1,las=0,now=0;
    for(int len=1;;las=now,len<<=1)
    {
	i64 prod=1,d;
	for(int i=1;i<=len;++i) if(now=mul(now,now,x)+c,prod=mul(prod,llabs(now-las),x),!(i&127)&&(d=std::__gcd(prod,x))!=1) return d;
	if((d=std::__gcd(prod,x))!=1) return d;
    }
}
void Factor(i64 x,int f)
{
    if(x==1) return ;
    if(Judge(x)) return cnt[x]+=f,void();
    i64 p=Find(x);int c=0;
    while(!(x%p))x/=p,++c;
    Factor(p,f*c),Factor(x,f);
}
void dfs(int c,i64 now,i64 val)
{
    if(c==tot+1)
    {
	if(now&1&&~(n/now)&1) return ;
	return inc(ans,mul(mul(pow(k,(now+1)/2,P),now/(now&1? 1:2),P),(val%P+P)%P,P));
    }
    i64 x=1;for(int i=0;i<=a[c].e;x*=a[c].p,++i) if(i==a[c].e) dfs(c+1,now*x,val); else dfs(c+1,now*x,val*(1-a[c].p));
}
void solve()
{
    cnt.clear(),ans=tot=0,Factor(n=read(),1),k=read(),P=read(),k%=P;
    for(auto it:cnt) a[++tot]={it.first,it.second};
    dfs(1,1,1),printf("%lld\n",ans);
}
int main()
{
    for(int t=read();t;--t) solve();
}
posted @ 2020-05-26 21:27  Shiina_Mashiro  阅读(174)  评论(0编辑  收藏  举报