神仙字符串结论题。
我们先进行一次操作变成一个 (SS) 串,然后考虑 (S) 的循环节 (G)。
- (G) 是 (S) 的整循环节
那么这个串会变成 (SGSG),(SGGSGG),...,(SGGGG...SGGGG....),由于是无限长我们只需考虑前半部分即可。这个直接求就行。
- (G) 不是 (S) 的整循环节
其实只是上一部分的扩展。
还是只用考虑前半部分,而前半部分的情况是 (S_i=S_{i-1}+S_{i-2}),也就是 (S),(SG),(SGS),(SGSSG)(其实样例已经给了提示)。
接下来我们来证明:
该结论等价于证明 (SG) 的最小循环节为 (S),且不会出现 (G) 变成整循环节的情况。设 (SG=T)
我们假设存在一个循环节 (p) 比 (S) 更短,那么 (p) 也是 (S) 的循环节,所以 (T[i]=T[i-p]) 由于 (G) 是 (S) 的前缀,所以 (T[i]=T[i-|S|]),又因为 (G) 是周期,所以 (i-pequiv i-|S|pmod |G|),(|p|equiv |S|pmod |G|),由于弱周期引理,(S) 有新的周期 (gcd(|p|,|G|)),所以 (p) 是 (|G|) 的倍数,所以 (|S|mod |G|=0) 矛盾!
于是我们直接暴力模拟即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2000005;
template <typename T>
void read(T &x) {
T flag = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
x *= flag;
}
char s[maxn];
int nxt[maxn];
ll l, r;
int n, m;
ll cnt[30], cntg[30], ans[30];
ll f[maxn];
ll cur[30], lst[30];
void solve(ll x, ll v) {
if (x == 0) return;
if (x <= n) {
for (int i = 1; i <= x; i++) ans[s[i] - 'a'] += v;
} else {
x -= n;
for (int i = 0; i < 26; i++) ans[i] = ans[i] + v * (cnt[i] + cntg[i] * (x / m));
for (int i = 1; i <= x % m; i++) ans[s[i] - 'a'] += v;
}
}
void dfs(ll x, ll v) {
if (x <= 0) return;
if (x <= n) {
for (int i = 1; i <= x; i++) ans[s[i] - 'a'] += v;
return;
}
f[1] = n, f[2] = n + m;
int now = 2;
for (int i = 0; i < 26; i++) cur[i] = cnt[i] + cntg[i], lst[i] = cnt[i];
while (f[now] <= x) {
if (now > 2) {
for (int i = 0; i < 26; i++) {
ll tmp = cur[i];
cur[i] += lst[i];
lst[i] = tmp;
}
}
f[now + 1] = f[now] + f[now - 1];
now++;
}
if (now == 2) {
for (int i = 0; i < 26; i++) ans[i] += lst[i] * v;
dfs(x - f[now - 1], v);
} else {
for (int i = 0; i < 26; i++) ans[i] += cur[i] * v;
dfs(x - f[now - 1], v);
}
}
int main() {
scanf("%s", s + 1);
read(l); read(r);
n = strlen(s + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && s[j + 1] != s[i]) j = nxt[j];
if (s[j + 1] == s[i]) j++;
nxt[i] = j;
}
int tmp = nxt[n];
while (tmp >= (n + 1) / 2) {
tmp = nxt[tmp];
}
n -= tmp;
for (int i = 1; i <= n; i++) cnt[s[i] - 'a']++;
m = n - nxt[n];
for (int i = 1; i <= m; i++) cntg[s[i] - 'a']++;
if (n % (n - nxt[n]) == 0) {
solve(r, 1); solve(l - 1, -1);
for (int i = 0; i < 26; i++) printf("%lld ", ans[i]);
} else {
dfs(r, 1); dfs(l - 1, -1);
for (int i = 0; i < 26; i++) printf("%lld ", ans[i]);
}
return 0;
}