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

题目链接

题目大意

求所有的串,满足其所有循环同构串中至少有一个串是回文串。
n 1 0 18 n\le 10^{18}

题解

第一步我就想偏了orz……我以为要分析这样串的性质……
考虑所有回文串,共有 k n 2 k^{\left\lceil\frac{n}{2}\right\rceil} 个,我们考虑把每个回文串第一个字符挪到后面,不断进行这样的操作,直到形成了新的回文串为止。假设这样操作了 t t 次,那么这个回文串的贡献就是 t t
比如baab,一次变成aabb,第二次变成abba,是个回文串,因此这个回文串的贡献是2.
考虑原串的最小整周期为 k k ,显然一个周期也是个回文串。若 k k 为奇数,那么贡献就是 k k ,否则贡献是 k 2 \frac k2
f ( i ) f(i) 表示周期为 i i 的因数的所有回文串个数, g ( i ) g(i) 表示最小整周期恰好为 i i 的所有回文串个数。则有:
f ( i ) = d i g ( d ) = 2 i 2 f(i)=\sum_{d|i}g(d)=2^{\left\lceil\frac{i}{2}\right\rceil}
再令 h ( i ) h(i) 表示最小整周期为 i i 时的贡献,即 i i 为奇数是 h ( i ) = i h(i)=i ,否则 h ( i ) = i 2 h(i)=\frac i2 。于是先使用莫比乌斯反演计算出 g g ,就可以统计答案了。
a n s = i n g ( i ) h ( i ) = i n h ( i ) d i μ ( d ) f ( i d ) = i n f ( i ) d n i μ ( d ) h ( i d ) ans=\sum_{i|n}g(i)h(i)=\sum_{i|n}h(i)\sum_{d|i}\mu(d)f(\frac id)\\ =\sum_{i|n}f(i)\sum_{d|\frac ni}\mu(d)h(id)
但是这样计算还是会超时,考虑后面那个sigma的性质。 h ( i d ) d h ( i ) h(id)\neq d\cdot h(i) 当且仅当 i i 为奇数且 d d 为偶数。如果 d d 是偶数,那么 n i \frac ni 也必然是偶数。此时考虑任意的奇数 x x ,必然有 μ ( x ) h ( i x ) + μ ( 2 x ) h ( 2 i x ) = 0 \mu(x)h(ix)+\mu(2x)h(2ix)=0 ,而如果后面sigma中的 d d 含有4这个因数的话 μ ( d ) = 0 \mu(d)=0 。因此:若 n i \frac ni 为偶数, i i 为奇数时后面的sigma取值为0.于是剩下来所有情况都是 h ( i d ) = d h ( i ) h(id)=d\cdot h(i) 了。
a n s = i n , i   i s   e v e n   o r n i i s   o d d f ( i ) h ( i ) d n i μ ( d ) d ans=\sum_{i|n,i~is~even~or \frac ni is ~odd}f(i)h(i)\sum_{d|\frac ni}\mu(d)d
显然后面那个sigma也是个积性函数,于是就可以得到:
d i μ ( d ) d = p n i , p   i s   p r i m e ( 1 p ) \sum_{d|i}\mu(d)d=\prod_{p|\frac ni,p~is~prime}(1-p)
于是这题再用Pollard-Rho分解一下 n n 就做完了。

#include <bits/stdc++.h>
namespace IOStream {
	const int MAXR = 1 << 23;
	char _READ_[MAXR], _PRINT_[MAXR];
	int _READ_POS_, _PRINT_POS_, _READ_LEN_;
	inline char readc() {
	#ifndef ONLINE_JUDGE
		return getchar();
	#endif
		if (!_READ_POS_) _READ_LEN_ = fread(_READ_, 1, MAXR, stdin);
		char c = _READ_[_READ_POS_++];
		if (_READ_POS_ == MAXR) _READ_POS_ = 0;
		if (_READ_POS_ > _READ_LEN_) return 0;
		return c;
	}
	template<typename T> inline void read(T &x) {
		x = 0; register int flag = 1, c;
		while (((c = readc()) < '0' || c > '9') && c != '-');
		if (c == '-') flag = -1; else x = c - '0';
		while ((c = readc()) >= '0' && c <= '9') x = x * 10 + c - '0';
		x *= flag;
	}
	template<typename T1, typename ...T2> inline void read(T1 &a, T2 &...x) {
		read(a), read(x...);
	}
	inline int reads(char *s) {
		register int len = 0, c;
		while (isspace(c = readc()) || !c);
		s[len++] = c;
		while (!isspace(c = readc()) && c) s[len++] = c;
		s[len] = 0;
		return len;
	}
	inline void ioflush() {
		fwrite(_PRINT_, 1, _PRINT_POS_, stdout), _PRINT_POS_ = 0;
		fflush(stdout);
	}
	inline void printc(char c) {
		_PRINT_[_PRINT_POS_++] = c;
		if (_PRINT_POS_ == MAXR) ioflush();
	}
	inline void prints(char *s) {
		for (int i = 0; s[i]; i++) printc(s[i]);
	}
	template<typename T> inline void print(T x, char c = '\n') {
		if (x < 0) printc('-'), x = -x;
		if (x) {
			static char sta[20];
			register int tp = 0;
			for (; x; x /= 10) sta[tp++] = x % 10 + '0';
			while (tp > 0) printc(sta[--tp]);
		} else printc('0');
		printc(c);
	}
	template<typename T1, typename ...T2> inline void print(T1 x, T2... y) {
		print(x, ' '), print(y...);
	}
}
using namespace IOStream;
using namespace std;
typedef long long ll;

const int B = 10, prime[B] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
ll modmul(ll a, ll b, ll c) {
	return (ll)((__int128)a * b % c);
}
ll modpowi(ll a, ll b, int c) {
	ll res = 1;
	for (a %= c; b; b >>= 1) {
		if (b & 1) res = res * a % c;
		a = a * a % c;
	}
	return res;
}
ll modpow(ll a, ll b, ll c) {
	ll res = 1;
	for (a %= c; b; b >>= 1) {
		if (b & 1) res = modmul(res, a, c);
		a = modmul(a, a, c);
	}
	return res;
}
int miller_rabin(ll p) {
	for (int i = 0; i < B; i++) {
		if (prime[i] == p) return 1;
		else if (p % prime[i] == 0) return 0;
	}
	ll t = p - 1; int l = 0;
	for (; !(t & 1); t >>= 1) ++l;
	for (int i = 0; i < B; i++) {
		ll x = modpow(prime[i], t, p);
		for (int j = 0; j < l; j++) {
			ll y = modmul(x, x, p);
			if (y == 1 && x != 1 && x != p - 1) return 0;
			x = y;
		}
		if (x != 1) return 0;
	}
	return 1;
}
ll pollard_rho(ll n) {
	ll x, y = x = rand() % (n - 1) + 1, c = rand() % (n - 1) + 1, k = 1;
	for (int i = 1;; i++) {
		x = (modmul(x, x, n) + c) % n;
		if (x == y) return 1;
		ll g = __gcd(n, x < y ? y - x : x - y);
		if (g > 1 && g < n) return g;
		if (i == k) y = x, k <<= 1;
	}
}
map<ll, int> mp;
vector<pair<ll, int> > vec;
void fact(ll n) {
	if (miller_rabin(n)) { ++mp[n]; return; }
	ll p; while ((p = pollard_rho(n)) == 1);
	fact(p), fact(n / p);
}
ll ans, n, k; int T, p;
void dfs(int d, ll num, ll mul) {
	if (d < 0) {
		if ((num & 1) && !(n & 1)) return;
		ll h = (num & 1 ? num : num >> 1) % p;
		(ans += modpowi(k, (num + 1) >> 1, p) * mul % p * h) %= p;
		return;
	}
	ll t = 1, q = vec[d].first, e = vec[d].second;
	for (int i = 0; i <= e; i++, t *= q)
		dfs(d - 1, num * t, mul * (i < e ? 1 - q : 1) % p);
}
int main() {
	srand(time(0));
	for (scanf("%d", &T); T--;) {
		scanf("%lld%lld%d", &n, &k, &p);
		if (n == 1) { printf("%lld\n", k % p); continue; }
		mp.clear(), vec.clear(), ans = 0; fact(n);
		for (auto a : mp) vec.push_back(a);
		dfs(vec.size() - 1, 1, 1);
		printf("%lld\n", (ans + p) % p);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/WAautomaton/article/details/87204580