[NOI2018]你的名字
主要题意
求字符串$S$与$T$不同的子串总数
题解
先考虑$l = 1, r = |T|$的情况:
因为任意子串为字符串前缀的某些后缀,那么令$Lim[i]$表示$T[1...i]$在$S$上所能匹配的最大长度,$Posi[i]$表示$T$的后缀自动机上的点$i$的$endpos$集合中最靠前的位置,那么答案即为
$$Ans = \sum\limits_{i = 1}^{nodes} \max (0, Len[i] - min (Len[Father[i]], Lim[Posi[i]]))$$
接下来考虑$l, r$任意的情况:
原来能否在$S$的后缀自动机上往下走的判断依据只有当前节点是否存在$c$边,那么有了$l, r$的限制,就多需要判断向下的这个节点的$endpos$是否有存在于$[l + len, r]$($len$表示已匹配长度)区间的位置,$endpos$集合用动态开点线段树维护一下就好了
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 typedef long long LL; 8 9 const int MAXN = 2e06 + 10; 10 const int MAXL = 20 + 5; 11 12 const int INF = 0x7fffffff; 13 14 int N, M, Q; 15 char Orig[MAXN], Str[MAXN]; 16 17 int Root[MAXN]= {0}; 18 int Left[MAXN * MAXL]= {0}, Right[MAXN * MAXL]= {0}; 19 int tnodes = 0; 20 void Modify (int& root, int left, int right, int pos) { 21 if (! root) 22 root = ++ tnodes; 23 if (left == right) 24 return ; 25 int mid = (left + right) >> 1; 26 pos <= mid ? Modify (Left[root], left, mid, pos) : Modify (Right[root], mid + 1, right, pos); 27 } 28 int Tree_Merge (int sl, int sr) { 29 if (! sl || ! sr) 30 return sl + sr; 31 int p = ++ tnodes; 32 Left[p] = Tree_Merge (Left[sl], Left[sr]); 33 Right[p] = Tree_Merge (Right[sl], Right[sr]); 34 return p; 35 } 36 bool Query (int root, int left, int right, int L, int R) { 37 if (! root || left > right) 38 return false; 39 if (L <= left && right <= R) 40 return true; 41 int mid = (left + right) >> 1; 42 if (L <= mid) 43 if (Query (Left[root], left, mid, L, R)) 44 return true; 45 if (R > mid) 46 if (Query (Right[root], mid + 1, right, L, R)) 47 return true; 48 return false; 49 } 50 51 struct SAM { 52 int Tree[MAXN][30]; 53 int Father[MAXN]; 54 int Len[MAXN], Posi[MAXN]; 55 int last, nodes; 56 57 void init () { 58 for (int i = 1; i <= nodes; i ++) { 59 memset (Tree[i], 0, sizeof (Tree[i])); 60 Father[i] = 0, Posi[i] = 0; 61 } 62 last = nodes = 1; 63 } 64 65 void Append (int c, int pos, int type) { 66 int fa = last, p = ++ nodes; 67 last = p; 68 Len[p] = Len[fa] + 1, Posi[p] = pos; 69 while (fa && ! Tree[fa][c]) 70 Tree[fa][c] = p, fa = Father[fa]; 71 if (! fa) 72 Father[p] = 1; 73 else { 74 int x = Tree[fa][c]; 75 if (Len[x] == Len[fa] + 1) 76 Father[p] = x; 77 else { 78 int np = ++ nodes; 79 Len[np] = Len[fa] + 1, Father[np] = Father[x], Posi[np] = Posi[x]; 80 Father[p] = Father[x] = np; 81 memcpy (Tree[np], Tree[x], sizeof (Tree[x])); 82 while (fa && Tree[fa][c] == x) 83 Tree[fa][c] = np, fa = Father[fa]; 84 } 85 } 86 if (type == 1) 87 Modify (Root[p], 1, N, pos); 88 } 89 int Topo[MAXN]; 90 int Minp[MAXN]; 91 int buck[MAXN]; 92 /*void Merge_Minp () { 93 for (int i = 1; i <= nodes; i ++) 94 buck[i] = 0, Minp[i] = Posi[i]; 95 for (int i = 1; i <= nodes; i ++) 96 buck[Len[i]] ++; 97 for (int i = 1; i <= N; i ++) 98 buck[i] += buck[i - 1]; 99 for (int i = nodes; i >= 1; i --) 100 Topo[buck[Len[i]] --] = i; 101 for (int i = nodes; i >= 1; i --) 102 Minp[Father[Topo[i]]] = min (Minp[Father[Topo[i]]], Minp[Topo[i]]); 103 }*/ 104 void Merge_Tree () { 105 for (int i = 1; i <= nodes; i ++) 106 buck[i] = 0; 107 for (int i = 1; i <= nodes; i ++) 108 buck[Len[i]] ++; 109 for (int i = 1; i <= N; i ++) 110 buck[i] += buck[i - 1]; 111 for (int i = nodes; i >= 1; i --) 112 Topo[buck[Len[i]] --] = i; 113 for (int i = nodes; i >= 1; i --) 114 Root[Father[Topo[i]]] = Tree_Merge (Root[Father[Topo[i]]], Root[Topo[i]]); 115 } 116 } ; 117 SAM S, T; 118 119 int Lim[MAXN]= {0}; 120 /*void Match (int l, int r) { 121 int p = 1, len = 0; 122 for (int i = 1; i <= M; i ++) { 123 int c = Str[i] - 'a'; 124 while (p && ! S.Tree[p][c]) 125 p = S.Father[p], len = S.Len[p]; 126 while (p && ! Query (Root[S.Tree[p][c]], 1, N, l + len, r)) 127 p = S.Father[p], len = S.Len[p]; 128 S.Tree[p][c] ? (p = S.Tree[p][c], len ++) : (p = 1, len = 0); 129 Lim[i] = len; 130 } 131 }*/ 132 void Work (int l, int r) { 133 int p = 1, len = 0; 134 for (int j = 1; j <= M; j ++) { 135 int c = Str[j] - 'a'; 136 T.Append (c, j, 2); 137 while (true) { 138 if (S.Tree[p][c] && Query (Root[S.Tree[p][c]], 1, N, l + len, r)) { 139 p = S.Tree[p][c], len ++; 140 break; 141 } 142 if (! len) 143 break; 144 len --; 145 if (len == S.Len[S.Father[p]]) 146 p = S.Father[p]; 147 } 148 Lim[j] = len; 149 } 150 // T.Merge_Minp (); 151 // Match (l, r); 152 } 153 154 LL Solve () { 155 LL ans = 0; 156 for (int i = 1; i <= T.nodes; i ++) 157 ans += max (0, T.Len[i] - max (T.Len[T.Father[i]], Lim[T.Posi[i]])); 158 return ans; 159 } 160 161 int getnum () { 162 int num = 0; 163 char ch = getchar (); 164 165 while (! isdigit (ch)) 166 ch = getchar (); 167 while (isdigit (ch)) 168 num = (num << 3) + (num << 1) + ch - '0', ch = getchar (); 169 170 return num; 171 } 172 173 int main () { 174 scanf ("%s", Orig + 1); 175 N = strlen (Orig + 1); 176 S.init (); 177 for (int i = 1; i <= N; i ++) 178 S.Append (Orig[i] - 'a', i, 1); 179 S.Merge_Tree (); 180 scanf ("%d", & Q); 181 for (int i = 1; i <= Q; i ++) { 182 scanf ("%s", Str + 1); 183 int l = getnum (), r = getnum (); 184 T.init (); 185 M = strlen (Str + 1); 186 Work (l, r); 187 LL ans = Solve (); 188 printf ("%lld\n", ans); 189 } 190 191 return 0; 192 } 193 194 /* 195 scbamgepe 196 3 197 smape 1 9 198 sbape 1 9 199 sgepe 1 9 200 */ 201 202 /* 203 scbamgepe 204 3 205 smape 2 7 206 sbape 3 8 207 sgepe 1 9 208 */