http://acm.hdu.edu.cn/showproblem.php?pid=6661
多校被虐得自闭,我还是太菜了
题意:很简单,就是问你有多个子串,能过被分割成相等的k个子串部分,不能有重复,比如aa可以分成两个a,ababab这能分成三个ab。
做法:首先想怎么做,肯定子串的长度是k的整数倍,我们枚举长度显然是不合理的。
我们换一种思路,枚举一个长度len的整数倍,判断有多少个子串以len为周期循环,那么就可以轻松得出答案了。
比如我们看看题解上的那个样例 s=abcabcabdabd 对于len=3有两个这样的子串 abcabcab,他的循环节是3,他的长度是8因此容易得出答案的贡献就是 8-3*k+1,当然要大于零才加上,这个如果对于k=2,就有三个abcabc bcabca cabcab,第二个字符串abdabd只有一个了。这样我们枚举一个x然后判断连续的x段是否相等,就可以了,如果有相邻不相等,我们要求得相邻两段它们的公共前缀的LCP,然后再求判断,对于答案有没有贡献(本题重点就是求这个)。同时关于下一端的起点我们要通过它们的公共后缀的LCP来判断,比如aabbabb,当长度枚举到3时,首先时aab和bab不相同,然后显然我们下次枚举的线段应该是abb和abb这个就是公共后缀有关了。如果没清楚自己yy一下吧,还不清楚欢迎下面评论。
标程是后缀数组,哎,写不来了,看也没有看懂。。。。。
就随便写了一个hash,hash二分求前后缀的LCP
因为复杂度的是.再加上一个hash二分,最多多算一个logn,考虑最坏的情况每一次都要判断前后缀的LCP,但不过这个logn无视,一秒钟稳稳的。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1000000 + 10;
///const ull base = 201326611;
const ull base = 131;
char str[N];
int k;
ull ha[N], p[N];
ull getha(int l, int r) {
if (l == 0) return ha[r];
return ha[r] - ha[l - 1] * p[r - l + 1];
}
int pre_check(int l, int ql, int len) {
int L = 0, R = len;
int mid, ret;
while (L <= R) {
mid = (L + R) >> 1;
if (getha(l, l + mid - 1) == getha(ql, ql + mid - 1)) {
ret = mid;
L = mid + 1;
} else R = mid - 1;
}
return ret;
}
int suffix_check(int r, int qr, int len) {
int L = 0, R = len;
int mid, ret;
while (L <= R) {
mid = (L + R) >> 1;
if (getha(r - mid + 1, r) == getha(qr - mid + 1, qr)) {
ret = mid;
L = mid + 1;
} else R = mid - 1;
}
return ret;
}
void solve(int len) {
ll ans = 0;
for (int x = 1; x <= len; x++) {
int cnt = 0, i = 0;
ull last = 0, tmp;
int t = x;
while (i < len) {
if (i + t - 1 >= len) t = len - i;
tmp = getha(i, i + t - 1);
if (last == 0) {
last = tmp, cnt = 1, i += x;
continue;
}
if (last == tmp) {
cnt++;
i += x;
} else {
ll l1 = pre_check(i - x, i, t);
ll l2 = suffix_check(i + t - 1, i - 1, t);
ll l = cnt * x + l1;
if (l >= k * x) ans += l - k * x + 1;
i += x - l2;
last = getha(i - x, i - 1), cnt = 1;
}
}
if (cnt >= k) {
ll l1 = pre_check(i - x, i, t);
ll l = cnt * x + l1;
if (l >= k * x) ans += l - k * x + 1;
}
}
printf("%lld\n", ans);
}
int main() {
p[0] = 1;
for (int i = 1; i < N; i++) p[i] = p[i - 1] * base;
int T;
cin >> T;
while (T--) {
cin >> k >> str;
int len = strlen(str);
if (k == 1) {
printf("%lld\n", 1ll * len * (len + 1) / 2);
continue;
}
ha[0] = (ull) str[0];
for (int i = 1; i < len; i++)
ha[i] = ha[i - 1] * base + str[i];
solve(len);
}
return 0;
}