Vexoben
Apr 10, 2019
题目链接:51nod1317 相似字符串对
题意
称一对字符串(A,B)是相似的,当且仅当满足以下条件:
(1)字符串A和B都恰好包含N个字符;
(2)A和B串中的每个字符都是小写字母的前k个字符,即A、B中只可能出现’a’,’b’,’c’,…,(’a’+k-1)这k个字符;
(3)存在一个字符串C,满足:A+C=C+B。这里的“+”号表示字符串间的链接,即str1+str2 = str1str2,如:“aaa”+“csd”=“aaacsd”。
例如,N=3,k=4那么(”aad”,”daa”)就是相似字符串对。
因为C=”aa”时,有”aad”+”aa”=”aadaa”=”aa”+”daa”.
现在给出N与k,问有多少种不同的相似字符串对,输出这个结果 mod 1,000,000,007的值。
说明:两个字符串对(A,B)与(C,D)是不同的,只要 A!=C 或 B!= D。
数据范围:n≤1e9,k≤26
题解
这题有两个十分重要的结论:
1、字符串 (A, B) 相似当且仅当 A 与 B 循环同构
证明只需要考虑两种情况,看下面的图应该就很显然了。
2、一个最小循环节长度为 k 的字符串 A ,可以有 k 个对应的 B 与之循环同构
于是只要 dp[i] 表示长度为 i 且最小循环长度为 i 的字符串数量,那么答案是 sum( i * dp[i]),复杂度应该是 n 的因子个数的平方。
#include<bits/stdc++.h>
using namespace std;
const int N = 1505;
const int mod = 1e9 + 7;
int n, k;
int cnt, f[N], fat[N];
inline void upd(int &x, register int y) {
static int z;
x = ((z = x + y) >= mod) ? (z - mod) : z;
}
int Qpow(int x, int p) {
int ans = 1;
while (p) {
if (p & 1) ans = 1LL * ans * x % mod;
x = 1LL * x * x % mod;
p >>= 1;
}
return ans;
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i * i <= n; ++i) {
if (n % i != 0) continue;
fat[++cnt] = i;
if (i * i != n) fat[++cnt] = n / i;
}
sort(fat + 1, fat + cnt + 1);
for (int i = 1; i <= cnt; ++i) {
f[i] = Qpow(k, fat[i]);
for (int j = 1; j < i; ++j) {
if (fat[i] % fat[j] == 0) {
upd(f[i], mod - f[j]);
}
}
}
int ans = 0;
for (int i = 1; i <= cnt; ++i) {
upd(ans, 1LL * fat[i] * f[i] % mod);
}
cout << ans << endl;
return 0;
}