作词(write)

题目描述

lovelive预赛要求原创歌曲,所以小海要准备新歌的词。小海有一段模板串ai,长度为n,她可以在模板串中选择一个区间的子串来作为歌词。但是已经有m个区间[li,ri]的子串被当做歌词了。为了保证原创,小海这次选出来的子串中不能出现之前给出的m个子串。小海想知道有多少可行的区间可以选择。

输入

第一行2个数 n,m

第二行一个字符串ai

接下来m行,每行两个数li,ri

输出

一个数表示答案

样例输入

6 2
aabaac
2 3
5 6

样例输出

10

提示

数据范围:

20% n,m<=100

另外20% ri-li<=10

另外 20% sigma ri-li<=n

另外0% 没有两个已被选出的子串互相包含

100% n,m<=3e5

考虑以$i$为结尾的串,合法的左端点都是一段连续的区间,形如$[l,i-1]$

令$f[i]=l$

那么考虑一段区间$[l,r]$,它会对所有包含他的后缀$b$的$f[b]$产生$b-(r-l+1)+1+1$的贡献。

注意贡献要取$max$,另外有$f[i]=max(f[i],f[i-1])$。

用后缀自动机来干这个事情就行了。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define M 600010
  4 #define LL long long
  5 #define inf 1047483647
  6 int tranc[M][27];
  7 int len[M], fa[M];
  8 int ri[M];
  9 int cnt = 1, tail = 1;
 10 int c[M], od[M];
 11 int ft[M][20];
 12 int mn[M];
 13 int wh[M];
 14 struct Edge{
 15     int u, v, Next;
 16 } G[M];
 17 int head[M], tot;
 18 inline void add(int u, int v) {
 19     G[++ tot] = (Edge){u, v, head[u]};
 20     head[u] = tot;
 21 }
 22 inline void insert(int k) {
 23     int p = tail, np = ++ cnt, q, nq;
 24     len[np] = len[p] + 1;
 25     ri[np] = 1;
 26     for(; p && !tranc[p][k]; p = fa[p]) {
 27         tranc[p][k] = np;
 28     }
 29     if(!p) fa[np] = 1;
 30     else {
 31         q = tranc[p][k];
 32         if(len[q] == len[p] + 1) fa[np] = q;
 33         else {
 34             fa[nq = ++ cnt] = fa[q];
 35             memcpy(tranc[nq], tranc[q], sizeof(tranc[q]));
 36             fa[q] = fa[np] = nq;
 37             len[nq] = len[p] + 1;
 38             for(; tranc[p][k] == q; p = fa[p]) {
 39                 tranc[p][k] = nq;
 40             }
 41         }
 42     }
 43     tail = np;
 44 }
 45 inline void init(int m) {
 46     for(int i = 1; i <= cnt; ++ i) c[len[i]] ++, mn[i] = inf;
 47     for(int i = 1; i <= m; ++ i) c[i] += c[i - 1];
 48     for(int i = cnt; i >= 1; -- i) od[c[len[i]] --] = i;
 49     for(int i = cnt; i >= 1; -- i) {
 50         ri[fa[od[i]]] += ri[od[i]];
 51     }
 52     memset(head, -1, sizeof(head));
 53     for(int i = 2; i <= cnt; ++ i) {
 54         add(fa[i], i);
 55         ft[i][0] = fa[i];
 56     }
 57     for(int i = 1; i <= 19; ++ i) {
 58         for(int j = 1; j <= cnt; ++ j) {
 59             ft[j][i] = ft[ft[j][i - 1]][i - 1];
 60         }
 61     }
 62 }
 63 int L[M], R[M], id[M];
 64 int dfs_clock, f[M], h[M];
 65 inline void dfs(int x, int g) {
 66     id[L[x] = ++ dfs_clock] = x;
 67     int j = g;
 68     if(mn[x] != inf) j = 1; 
 69     for(int i = head[x]; i != -1; i = G[i].Next) {
 70         dfs(G[i].v, j);
 71     }
 72     R[x] = dfs_clock;
 73     if(!g && j) {
 74         for(int i = L[x]; i <= R[x]; ++ i) {
 75             int b = h[id[i]]; 
 76             if(b) f[b] = max(f[b], b - mn[x] + 2);
 77         } 
 78     }
 79 }
 80 char s[M];
 81 int main() {
 82     int n, m;
 83     scanf("%d%d", &n, &m);
 84     scanf("%s", s + 1);
 85     for(int i = 1; i <= n; ++ i) {
 86         insert(s[i] - 'a');
 87         wh[i] = tail; 
 88         h[tail] = i;
 89     }
 90     init(cnt);
 91     for(int i = 1; i <= m; ++ i) {
 92         int l, r;
 93         scanf("%d%d", &l, &r);
 94         int o = wh[r];
 95         for(int j = 19; j >= 0; -- j) {
 96             if(len[ft[o][j]] >= r - l + 1) {
 97                 o = ft[o][j];
 98             }
 99         }
100         mn[o] = min(mn[o], r - l + 1);
101     }
102     for(int i = 1; i <= n; ++ i) f[i] = 1;
103     dfs(1, 0);
104     LL Ans = 0;
105     for(int i = 1; i <= n; ++ i) {
106         Ans += i - f[i] + 1;
107         f[i + 1] = max(f[i + 1], f[i]);
108     }
109     printf("%lld
", Ans);
110 }
原文地址:https://www.cnblogs.com/iamqzh233/p/9445726.html