Solution S o l u t i o n
要求的就是长度为
n
n
的可通过循环位移得到回文串的串的本质不同的个数。
我们考虑枚举长度为 的回文串作为其最小循环节来计数。
可以发现回文串的循环节也是循环的。那长度为
x
x
的循环节为 种。
但这样求出来的并不是作为最小循环节的方案数,而是
x
x
的约数的方案数的前缀和。容斥掉就好了。
那么最后得到了每个长度 作为最小循环节的。
根据循环节是回文串,就知道奇数
x
x
的贡献是 ,偶数
x
x
的贡献是 。
复杂度就是
O(σ20(n))
O
(
σ
0
2
(
n
)
)
的了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1000000007;
int n, k, ans;
vector<int> fac, dp;
inline int pwr(int a, int b) {
int c = 1;
while (b) {
if (b & 1) c = (ll)c * a % MOD;
b >>= 1; a = (ll)a * a % MOD;
}
return c;
}
inline void add(int &x, int a) {
x = (x + a >= MOD) ? x + a - MOD : x + a;
}
inline void sub(int &x, int a) {
x = (x < a) ? x - a + MOD : x - a;
}
int main(void) {
cin >> n >> k;
int m = sqrt(n);
for (int i = 1; i <= m; i++)
if (n % i == 0) {
fac.push_back(i);
fac.push_back(n / i);
}
sort(fac.begin(), fac.end());
fac.erase(unique(fac.begin(), fac.end()), fac.end());
dp.resize(fac.size());
for (int i = 0; i < fac.size(); i++) {
dp[i] = pwr(k, (fac[i] + 1) / 2);
for (int j = 0; j < i; j++)
if (fac[i] % fac[j] == 0)
sub(dp[i], dp[j]);
if (fac[i] & 1) add(ans, (ll)dp[i] * fac[i] % MOD);
else add(ans, (ll)dp[i] * fac[i] / 2 % MOD);
}
cout << ans << endl;
return 0;
}