[武汉加油] 2020.3.17考试T3 string

一个长度为 (n) 字符集大小为 (k) 的字符串,它的回文串的个数是 (k^{lceil frac{n}{2} ceil})

发现根据题目里给的操作二, 可以生成 最小循环节的长度 个满足条件的字符串,

用这个长度的字符串拼出来长为 (n) 的字符串必须是回文串

设这个长度为 (l),满足这个长度(能拼成长为 (n) 的回文串)的字符串个数是 (f[l]) ,那么对答案的贡献就是 (l imes f[l]).

(f) 容斥计算一下即可。

#include<algorithm>
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
LL n, k, tot, ans;
const int mod = 1e9 + 7, N = 2005;
LL w[N], f[N];
LL ksm(LL a, LL b, LL mod)
{
	LL res = 1;
	for (; b; b >>= 1, a = a * a % mod)
		if (b & 1)res = res * a % mod;
	return res;
}
int main()
{
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	cin >> n >> k;
	for (int i = 1; i * i <= n; ++i)
		if (!(n % i))
		{
			w[++tot] = i;
			if (i * i != n)w[++tot] = n / i;
		}
	sort(w + 1, w + 1 + tot);
	for (int i = 1; i <= tot; ++i)
	{
		f[i] = ksm(k, (w[i] + 1) / 2, mod);
		for (int j = 1; j < i; ++j)
			if (!(w[i] % w[j]))f[i] = (f[i] - f[j] + mod) % mod;
		if (w[i] & 1)ans = (ans + f[i] * w[i]) % mod;
		else ans = (ans + f[i] * (w[i] / 2)) % mod;
	}
	cout << ans;
	fclose(stdin); fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/wljss/p/12513047.html