Description
“回文串什么的最讨厌了……”
小Q讨厌任何形式的回文串:
(1)如果一个字符串从左往右读和从右往左读是一样的,那么小Q讨厌它;例如aa和aba
(2)对于一个字符串来说,若将某个前缀子串移除并拼接到字符串的尾部,能得到一个小Q讨厌的字符串,
那么小Q也会讨厌原来的这个字符串;例如aab和baa。
现在问题来了,如果任意字符串只可以由k种已知的字符组成(也就是说字符集的大小为k),
那么长度为n的所有字符串里,有多少字符串是小Q讨厌的?
答案可能很大,你只需要给出答案对p取模后的值。
Input
第一行包含一个正整数T,表示有T组测试数据。
接下来T行,每行描述一组测试数据,包含三个正整数n,k和p。
1<=T<=10,1<=n<=10^18,1<=k<=n,10^9<=p<=2^30
Output
对于每组测试数据,输出一行,包含一个整数,表示答案对p取模的值。
Sample Input
10
9311702400 2063322107 1032035101
9311702400 3847844404 1014424217
9311702400 6992683534 1067435323
9311702400 1356819643 1024817347
9311702400 6944668829 1042812553
9311702400 9162670852 1003177793
9311702400 6567188538 1062813337
9311702400 3910301217 1018910293
9311702400 2463242636 1018694167
9311702400 4797739673 1050709027
Sample Output
618961590
28597316
1016219343
977847638
108994801
100559666
694084378
492868358
336126742
176095716
解题思路:
原来SDOI2018的莫比乌斯反演在这里……
考虑一个长度为 回文串,将其循环移位后所有的串都是满足要求的串。
但是显然这样计算会算重。考虑什么情况下会算重。
即当我们将这个回文串移位x后,发现这个新字符串为一个回文串时,必然接下来的移位都是重复的。
那么当x为多少时,新字符串为一个回文串?
我们稍加分析就会发现x一定和回文串的最小循环节 有关。
考虑最小循环节若为偶数时,当 时,则会变为一个新的回文串。
否则, 时,会出现一个新的回文串。
那么我们设 表示长度为n,字符集为k,最小循环节为d的字符串的数量。
显然会有 。
设 。
由莫比乌斯反演则有 。
那么
我们设
,那么:
注意只有当 为奇数, 为偶数时 ,因为此时 和 (x为奇数)一一对应,所以和为0。
其余情况下很容易证明
,所以:
而
正是
(
是
的质因数分解) 的展开式,所以:
用Miller-Robin算法将n分解质因数后枚举因数即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll getint()
{
ll i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
ll n,k,mod,m,ans,yz[100];
map<ll,int>mp;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll mul(ll x,ll y,ll p)
{
ll res=x*y-(ll)((long double)x*y/p+0.5)*p;
return res<0?res+p:res;
}
ll Pow(ll x,ll y,ll p)
{
ll res=1;x%=p;
for(;y;y>>=1,x=mul(x,x,p))
if(y&1)res=mul(res,x,p);
return res;
}
bool check(ll x,ll n,ll r,ll s)
{
x=Pow(x,r,n);ll pre=x;
while(s--)
{
x=mul(x,x,n);
if(x==1&&pre!=1&&pre!=n-1)return false;
pre=x;
}
return x==1;
}
bool MR(ll n)
{
if(n==1)return false;
if(n==2)return true;
if(!(n&1))return false;
ll r=n-1,s=0;
while(!(r&1))r>>=1,s++;
for(int i=0;i<9;i++)if(!check(rand()%(n-1)+1,n,r,s))return false;
return true;
}
ll pho(ll n,ll c)
{
ll x=rand()%n,y=x,k=2,p=1;
for(int i=1;p==1;i++)
{
x=(mul(x,x,n)+c)%n;
p=gcd(n,abs(x-y));
if(i==k)y=x,k<<=1;
}
return p;
}
void solve(ll n)
{
if(n==1)return;
if(MR(n))
{
if(!mp[n])yz[++m]=n;
mp[n]++;return;
}
ll t=n;while(t==n)t=pho(n,rand()%(n-1)+1);
solve(t),solve(n/t);
}
void dfs(int i,ll d,ll s)
{
if(i==m+1)
{
if((d&1)&&(!(n/d&1)))return;
ans=(ans+mul(Pow(k,(d+1)/2,mod),((d&1)?d:d/2),mod)*(s%mod+mod)%mod)%mod;
return;
}
int cnt=mp[yz[i]];ll t=1;
while(cnt--)dfs(i+1,d*t,s*(1-yz[i])),t*=yz[i];
dfs(i+1,d*t,s);
}
void solve()
{
n=getint(),k=getint(),mod=getint();
m=0,mp.clear(),solve(n);
ans=0,dfs(1,1,1);
printf("%lld\n",ans);
}
int main()
{
//freopen("cycpal.in","r",stdin);
for(int T=getint();T;T--)solve();
}