http://codeforces.com/contest/316/problem/G3
利用RMQ 求 後綴的前綴在每個串裏面的個數
二分每個後綴滿足要求的最大和最小前綴長度
我用了十個後綴數組
代碼寫得有些拖沓
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const int INF = 0x7f7f7f7f;
const int maxn = 111111;
const int mod = 1000000000;
const double eps = 1e-10;
char s[maxn];
char ss[12][maxn];
int A[20], B[20];
int Log[20];
int a[maxn], wa[maxn], wb[maxn], wv[maxn], wn[maxn];
int tp[maxn];
struct range_min_query {
int i, j, k, r[18][maxn];
void make(int n, int arr[]) {
for (i = 0; i <= n; ++i)
r[0][i] = arr[i];
for (i = 0; i < 17; ++i) {
k = Log[i];
for (j = 0; j + k <= n; ++j)
r[i + 1][j] = min(r[i][j], r[i][j + k]);
}
}
int query(int L, int R) {
if (R == L)
return r[k][L];
k = tp[R - L];
return min(r[k][L], r[k][R - Log[k]]);
}
} RMQ[10];
struct suffix_array {
int sum[maxn], sa[maxn], rank[maxn], h[maxn];
bool cmp(int r[], int a, int b, int l) {
return (r[a] == r[b] && r[a + l] == r[b + l]);
}
void Da(int r[], int n, int m) {
int i, j, p, *t;
int *x = wa, *y = wb;
for (i = 0; i < m; ++i)
wn[i] = 0;
for (i = 0; i < n; ++i)
wn[x[i] = r[i]]++;
for (i = 1; i < m; ++i)
wn[i] += wn[i - 1];
for (i = n - 1; i >= 0; --i)
sa[--wn[x[i]]] = i;
for (j = 1, p = 1; p < n; j <<= 1, m = p) {
for (p = 0, i = n - j; i < n; ++i)
y[p++] = i;
for (i = 0; i < n; ++i)
if (sa[i] >= j)
y[p++] = sa[i] - j;
for (i = 0; i < n; ++i)
wv[i] = x[y[i]];
for (i = 0; i < m; ++i)
wn[i] = 0;
for (i = 0; i < n; ++i)
wn[wv[i]]++;
for (i = 1; i < m; ++i)
wn[i] += wn[i - 1];
for (i = n - 1; i >= 0; --i)
sa[--wn[wv[i]]] = y[i];
p = 1, t = x, x = y, y = t;
for (x[sa[0]] = 0, i = 1; i < n; ++i)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
}
}
void Calheight(int r[], int n) {
int i, j, k = 0;
for (i = 1; i <= n; ++i)
rank[sa[i]] = i;
for (i = 0; i < n; h[rank[i++]] = k)
for (k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k)
;
}
int left(int l, int r, int k, range_min_query& RMQ) {
int m, p = r, t, ans = r;
while (l <= r) {
m = (l + r) >> 1;
t = RMQ.query(m + 1, p + 1);
if (t >= k)
ans = m, r = m - 1;
else
l = m + 1;
}
return ans;
}
int right(int l, int r, int k, range_min_query& RMQ) {
int m, p = l, t, ans = l;
while (l <= r) {
m = (l + r) >> 1;
t = RMQ.query(p + 1, m + 1);
if (t >= k)
ans = m, l = m + 1;
else
r = m - 1;
}
return ans;
}
int search(int p, int len, int k, range_min_query& RMQ) {
int L, R;
L = left(1, p, k, RMQ);
R = right(p, len, k, RMQ);
return getsum(L, R);
}
void Calsum(int n, int len) {
sum[0] = 0;
for (int i = 1; i <= n; ++i)
sum[i] = sum[i - 1] + (sa[i] > len && sa[i] < n);
}
int getsum(int L, int R) {
return sum[R] - sum[L - 1];
}
} suffix[10], src;
int tlen[15];
bool low(int i, int n, int L) {
int l, r, tmp;
for (int k = 0; k < n; ++k) {
l = suffix[k].rank[i];
r = tlen[k];
tmp = suffix[k].search(l, r, L, RMQ[k]);
if (tmp > B[k])
return false;
}
return true;
}
bool high(int i, int n, int L) {
int l, r, tmp;
for (int k = 0; k < n; ++k) {
l = suffix[k].rank[i];
r = tlen[k];
tmp = suffix[k].search(l, r, L, RMQ[k]);
if (tmp < A[k])
return false;
}
return true;
}
int main() {
int i, len, j;
Log[0] = 1;
for (i = 1; i < 20; ++i)
Log[i] = Log[i - 1] << 1;
tp[1] = 0;
i = 0;
for (j = 2; j < maxn; ++j) {
if (Log[i + 1] < j)
tp[j] = ++i;
else
tp[j] = i;
//printf("%d %d\n",j,tp[j]);
}
scanf("%s", s);
len = strlen(s);
for (i = 0; i <= len; ++i)
a[i] = (int) s[i];
src.Da(a, len + 1, 128);
src.Calheight(a, len);
for (i = 0; i < 10; ++i)
for (j = 0; j < len; ++j)
ss[i][j] = s[j];
int n;
scanf("%d", &n);
for (i = 0; i < n; ++i) {
ss[i][len] = '$';
scanf("%s%d%d", ss[i] + len + 1, A + i, B + i);
tlen[i] = strlen(ss[i]);
for (j = 0; j <= tlen[i]; ++j)
a[j] = (int) ss[i][j];
suffix[i].Da(a, tlen[i] + 1, 128);
suffix[i].Calheight(a, tlen[i]);
suffix[i].Calsum(tlen[i], len);
RMQ[i].make(tlen[i] + 1, suffix[i].h);
}
int L, R, p, m, l, r;
int ans = 0;
for (i = 0; i < len; ++i) {
p = src.rank[i];
L = src.h[p] + 1;
R = len - i;
l = -1, r = -2;
while (L <= R) {
m = (L + R) >> 1;
if (low(i, n, m))
l = m, R = m - 1;
else
L = m + 1;
}
L = src.h[p] + 1;
R = len - i;
while (L <= R) {
m = (L + R) >> 1;
if (high(i, n, m))
r = m, L = m + 1;
else
R = m - 1;
}
if (r != -2 && l != -1 && r >= l)
ans += (r - l + 1);
}
printf("%d\n", ans);
return 0;
}