SDOI2018 反回文串 (计数)(Pollard-Rho)(莫比乌斯反演)

传送门

一直没敢动,但发现前几天做过一道类似的回文串计数,发现这道题也没有想象中的难

考虑一个回文串能转出来几个不同的串
显然是循环节大小这么多个,考虑让一个回文串的贡献为它的循环节的大小
但发现这样子是算重了的,一个回文串有可能转出一个更它不同的回文串
发现这种情况只会在串长为偶数的情况出现一次,于是我们让偶数串的贡献为 1 / 2 1/2 的循环节大小即可
用一个函数 h ( n ) h(n) 来表示,当 2 n 2|n 时, h ( n ) = n 2 h(n)=\frac{n}{2} ,否则为 n n ,求的就是
a n s = d n f ( d ) h ( d ) ans=\sum_{d|n}f(d)h(d)
f ( d ) f(d) 表示循环节大小为 d d 长度为 n n 的回文串个数
考虑到令 g ( n ) g(n) 为长度为 n n 的回文串总个数,那么枚举循环节大小就可以不重不漏地统计 g g
g ( n ) = d n f ( d ) f ( n ) = d n μ ( n d ) g ( d ) g(n)=\sum_{d|n}f(d)\Leftrightarrow f(n)=\sum_{d|n}\mu (\frac{n}{d})g(d)
代入原式
A n s = d n h ( d ) l d μ ( d l ) g ( l ) = l n g ( l ) t l n h ( t l ) μ ( t ) Ans=\sum_{d|n}h(d)\sum_{l|d}\mu(\frac{d}{l})g(l)=\sum_{l|n}g(l)\sum_{tl|n}h(tl)\mu(t)
想办法把 h h 拆开, h ( t l ) t h ( l ) h(tl)\neq t*h(l) 当且仅当 t t 为偶数但 l l 为奇数
注意到如果 μ ( t ) 0 \mu(t)\neq 0 ,那么 t t 中只有一个 2,也就是说 μ ( t ) h ( t l ) = μ ( t 2 ) h ( t l 2 ) \mu(t)h(tl)=-\mu(\frac{t}{2})h(\frac{tl}{2}) ,奇偶抵消
所以,若 l l 为奇数, n l \frac{n}{l} 为偶数,那么
t n l μ ( t ) h ( t l ) = 0 \sum_{t|\frac{n}{l}}\mu(t)h(tl)=0
特判掉,于是有
A n s = l n g ( l ) h ( l ) t l n t μ ( t ) Ans=\sum_{l|n}g(l)h(l)\sum_{tl|n}t\mu(t)
如何快速求后面的一坨,有贡献的 μ \mu 一个质因子之多一个
考虑把所有质因子排成一排,重复的往上类,就是每一列可以选一个或者不选,贡献是 p ( 1 ) p*(-1)
类似构造生成函数,有
t l n t μ ( t ) = ( 1 p i ) \sum_{tl|n}t\mu(t)=\prod(1-p_i)
p o l l a r d   r h o pollard\ rho 分解
d f s dfs 求出质因子以及 ( 1 p i ) \prod(1-p_i) 即可

#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;
}
发布了610 篇原创文章 · 获赞 94 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/103623465