求字符集大小爲$k$長度爲$n$的經循環移位後爲迴文串的數量。c++
這題是D1裏最神的吧
算法
考慮一個長度爲$n$迴文串,將其循環移位後全部的串都是知足要求的串。優化
可是顯然這樣計算會算重。考慮什麼狀況下會算重。spa
即當咱們將這個迴文串移位$x$後,發現這個新字符串爲一個迴文串時,必然接下來的移位都是重複的。blog
那麼當$x$爲多少時,新字符串爲一個迴文串?字符串
咱們稍加分析就會發現x必定和迴文串的最小循環節$d$有關。get
考慮最小循環節若爲偶數時,當$x==d/2$時,則會變爲一個新的迴文串。it
反之,$x==d$時,會出現一個新的迴文串。class
那麼咱們設$F(d)$表示長度爲$n$,字符集爲$k$,最小循環節爲d的字符串的數量。循環
顯然會有$\sum_{d|n}F(d)==k^{\lceil \frac{n}{2}\rceil}$。
設$G(n)=k^{\lceil \frac{n}{2}\rceil}$。
由莫比烏斯反演則有$F(d)=\sum_{n|d}\mu(\frac{n}{d})G(n)$。
那麼考慮循環節$d$爲偶數的串對答案貢獻應該爲$\frac{d}{2}*F(d)$這個咱們在上面已經分析過了。
反之,則有其貢獻爲$d*F(d)$。
那麼$Ans=\sum_{d|n}F(d)\frac{d}{1+[d爲偶數]}$。
咱們設$H(d)=\frac{d}{1+[d爲偶數]}$。
觀察這個式子,發現直接求對於$1e18$的數據顯然會T。考慮繼續優化。
發現算法瓶頸在於$H(dm)$,思考$\sum_{d|x}\mu(d)*H(dm)$的性質。
因爲$H(dm)$的值與奇偶性有關,那麼咱們分類討論一下$m$和$\frac{n}{m}$之間奇偶性的關係。
考慮對於四種狀況,咱們(能夠通過打表或者推導)會發現,當$m$爲奇數且$\frac{n}{m}$爲偶數時,$\sum_{d|\frac{n}{m}}\mu(d)H(dm)$爲0,而另外三種狀況都是$H(m)\sum_{d|\frac{n}{m}}\mu(d)H(d)$。
#include "bits/stdc++.h" #define int long long using namespace std; inline int read () { int s=0,k=1;char ch=getchar(); while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); return s*k; } typedef long long ll; inline ll R(ll x) { return 1ll*rand()*rand()%x; } inline ll Mult ( ll a,ll b ,ll mod) { return ( a*b - (ll)( (long double) a*b/mod )*mod + mod )% mod; } inline ll powmod(ll a,ll b,ll mod) { ll ret=1; while (b) { if (b&1) ret = Mult(ret,a,mod); b>>=1;a=Mult(a,a,mod); } return ret; } int prim[] = {2,3,5,7,11}; inline int Miller_Rabin(ll n) { if (n==2) return true; int s=20,i,t=0; for (i=0;i<5;++i) if (n==prim[i]) return true; else if (n%prim[i]==0) return false; ll u=n-1,x[30]; while (!(u&1)) ++t,u>>=1; // printf("n=%lld u=%l\n",n); while (s--) { ll a=1ll*rand ()*rand()%(n-2)+2; x[0] = powmod (a,u,n); for (i=1;i<=t;++i) { x[i] = Mult(x[i-1],x[i-1],n); if (x[i]==1&&x[i-1]!=1&&x[i-1]!=n-1) return false; } if (x[t]!=1) return false ; } return true; } inline ll gcd (ll a,ll b) { return b?gcd(b,a%b):a; } inline ll Pollard_Rho(ll n,int c) { ll i=1,k=2,x=rand()%(n-1)+1,y=x; // printf("n=%lld\n",n); while (1) { ++i ; x = (Mult(x,x,n) + c)%n; ll p = gcd (y-x+n,n); if (p!=1&&p!=n) return p; if (y==x) return n; if (i==k) { y=x; k<<=1; } } } ll f[100],mod; int cnt; inline void find(ll n) { if (n==1) return ; // printf("%lld\n",n); if (Miller_Rabin(n)) { f[++cnt]=n; return ; } //while (n==13); ll p=n; while (p==n) p = Pollard_Rho(n,R(n-1)); // printf("p=%lld\n",p); find(p); find(n/p); } ll n,k; int m,num[100]; ll p[100][100]; ll ans; inline void add (ll &x,ll y) { x+=y; //printf("x=%lld y=%lld mod=%lld\n",x,y,mod); if (x>=mod) x-=mod; if (x<0) x+=mod; } inline void dfs(int step,ll d,ll S) { if (step>m) { if ((d&1)==0&&(n/d&1)) return ; ll tmp=n/d; //printf("tmp=%lld d=%lld\n",tmp,d); //printf("k=%lld %lld %lld %lld\n",k,powmod(k,(tmp+1)/2,mod),((tmp&1)?tmp:tmp/2),S); add ( ans , Mult(Mult(powmod(k,(tmp+1)/2,mod),((tmp&1)?tmp:tmp/2),mod),S,mod)); return ; } dfs (step+1,d,S); for (int i=1;i<=num[step];++i) dfs (step + 1, d*p[step][i],S*(1-p[step][1])); //printf("step=%d\n",step); } main () { //freopen("3.in","r",stdin); //freopen("3.out","w",stdout); int T=read(); while (T--) { scanf("%lld%lld",&n,&k),mod=read(); k%=mod; cnt=m=0; ans =0; find(n); sort(f+1,f+cnt+1); memset(p,0,sizeof p); for (int i=1,j=1;i<=cnt;i=j) { p[++m][0]=1; p[m][1]=f[i]; num[m]=1; // printf("p=%lld\n",f[i]); for (j=i+1;j<=cnt;++j) if (f[j]!=f[j-1]) break; else p[m][j-i+1]=p[m][j-i]*f[j]; num[m]=j-i; // printf("num=%lld\n",num[m]); } dfs(1,1,1); printf("%lld\n",ans); } return 0; }