一直没敢动,但发现前几天做过一道类似的回文串计数,发现这道题也没有想象中的难
考虑一个回文串能转出来几个不同的串
显然是循环节大小这么多个,考虑让一个回文串的贡献为它的循环节的大小
但发现这样子是算重了的,一个回文串有可能转出一个更它不同的回文串
发现这种情况只会在串长为偶数的情况出现一次,于是我们让偶数串的贡献为
的循环节大小即可
用一个函数
来表示,当
时,
,否则为
,求的就是
表示循环节大小为
长度为
的回文串个数
考虑到令
为长度为
的回文串总个数,那么枚举循环节大小就可以不重不漏地统计
代入原式
想办法把
拆开,
当且仅当
为偶数但
为奇数
注意到如果
,那么
中只有一个 2,也就是说
,奇偶抵消
所以,若
为奇数,
为偶数,那么
特判掉,于是有
如何快速求后面的一坨,有贡献的
一个质因子之多一个
考虑把所有质因子排成一排,重复的往上类,就是每一列可以选一个或者不选,贡献是
类似构造生成函数,有
分解
求出质因子以及
即可
#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
#define int long long
int Mod;
ll add(ll a, ll b, ll p){ return a + b >= p ? a + b - p : a + b; }
ll mul(ll a, ll b, ll p){ return (a*b-(ll)((long double)a/p*b)*p+p)%p; }
ll ksm(ll a, ll b, ll p){ ll ans=1; for(;b;b>>=1,a=mul(a,a,p)) if(b&1) ans=mul(ans,a,p); return ans; }
ll gcd(ll a, ll b){ return !b ? a : gcd(b, a % b); }
ll fix(ll a){ return (a % Mod + Mod) % Mod; }
cs int N = 1e7 + 5;
int prim[N], pc, mn[N]; bool isp[N];
void Sieve(int n){
for(int i = 2; i <= n; i++){
if(!isp[i]) prim[++pc] = i, mn[i] = i;
for(int j = 1; j <= pc; j++){
if(prim[j] * i > n) break; isp[prim[j] * i] = true;
mn[i*prim[j]] = mn[i]; if(i % prim[j] == 0) break;
}
}
}
cs int M = 1e6 + 5;
int T; ll k, n; ll p[M]; int tot, ct[M];
int c[20] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43};
bool Miller(ll p){
if(p <= 1e7) return !isp[p];
if(p % 2 == 0) return false;
for(int i = 0; i < 14; i++){
if(p % c[i] == 0) return false;
ll x = p-1, bit = 0;
while(x & 1 ^ 1) x >>= 1, ++bit;
ll cur = ksm(c[i], x, p);
for(int i = 0; i < bit; i++){
ll nxt = mul(cur, cur, p);
if(nxt == 1 && (cur != 1 && cur != p-1)) return false;
cur = nxt; if(cur == 1) break;
} if(cur != 1) return false;
} return true;
}
ll Solve(ll x){
if(x % 2 == 0) return 2;
if(x % 3 == 0) return 3;
if(x % 5 == 0) return 5;
if(x % 7 == 0) return 7;
ll n = 1, m = 1, c = rand() % (x-1) + 1;
for(ll k = 2; ; k <<= 1, m = n){
ll q = 1;
for(ll i = 0; i < k; i++){
n = add(mul(n, n, x), c, x);
q = mul(q, abs(m - n), x);
} ll t = gcd(q, x); if(t > 1) return t;
}
}
void Rho(ll x){
if(Miller(x)){ p[++tot] = x; return; }
if(x <= 1e7){
while(x>1){
p[++tot] = mn[x];
int nx = mn[x]; while(x % nx == 0) x /= nx;
} return;
}
ll p = x; while(p >= x) p = Solve(p);
Rho(p); while(x % p == 0) x/=p; Rho(x);
}
ll vl[M]; int num;
unordered_map<ll,ll> F;
void dfs(int u, ll val, ll coef){
if(u > tot){ vl[++num] = val; F[val] = coef; return; }
for(ll i = 0, nx = 1; i <= ct[u]; i++, nx *= p[u])
dfs(u + 1, val * nx, coef * (i ? (Mod+1 - fix(p[u])) : 1) % Mod);
}
void Clear(){ memset(ct,0,sizeof(int)*(tot+1)); num = tot = 0; F.clear(); }
void Solve(){
cin >> n >> k >> Mod; Rho(n); k %= Mod;
sort(p + 1, p + tot + 1);
tot = unique(p + 1, p + tot + 1) - (p + 1); ll nx = n;
for(int i = 1; i <= tot; i++){
while(nx % p[i] == 0) nx /= p[i], ++ct[i];
}
dfs(1, 1, 1); ll ans = 0;
for(int i = 1; i <= num; i++){
ll l = vl[i]; if((l&1)&&((n/l)&1^1)) continue;
ll G = ksm(k, ((l+1)/2), Mod) % Mod, H = (l&1?l:l/2) % Mod;
ans = (ans + G * H % Mod * F[n/l] % Mod) % Mod;
} cout << fix(ans) << '\n';
}
signed main(){
Sieve(1e7); srand(time(0));
cin >> T; while(T--) Solve(), Clear(); return 0;
}