[武汉加油] 2020.3.17考试T3 string

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

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

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

设这个长度为 \(l\),满足这个长度(能拼成长为 \(n\) 的回文串)的字符串个数是 \(f[l]\) ,那么对答案的贡献就是 \(l \times 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;
}
posted @ 2020-03-17 20:15  wljss  阅读(129)  评论(0编辑  收藏  举报