zoukankan      html  css  js  c++  java
  • [NOI2018]你的名字

    主要题意

    求字符串$S$与$T$不同的子串总数

    题解

    先考虑$l = 1, r = |T|$的情况:

    因为任意子串为字符串前缀的某些后缀,那么令$Lim[i]$表示$T[1...i]$在$S$上所能匹配的最大长度,$Posi[i]$表示$T$的后缀自动机上的点$i$的$endpos$集合中最靠前的位置,那么答案即为

    $$Ans = sumlimits_{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
    ", 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 */
    View Code
  • 相关阅读:
    一步一步学Silverlight 2系列(22):在Silverlight中如何用JavaScript调用.NET代码
    一步一步学Silverlight 2系列(16):数据与通信之JSON
    一步一步学Silverlight 2系列(9):使用控件模板
    一步一步学Silverlight 2系列(30):使用Transform实现更炫的效果(下)
    一步一步学Silverlight 2系列(31):图形图像综合实例—实现水中倒影效果
    一步一步学Silverlight 2系列(20):如何在Silverlight中与HTML DOM交互(下)
    一步一步学Silverlight 2系列(33):Silverlight 2应用Web Service两例
    一步一步学Silverlight 2系列(14):数据与通信之WCF
    一步一步学Silverlight 2系列(3):界面布局
    一步一步学Silverlight 2系列(6):键盘事件处理
  • 原文地址:https://www.cnblogs.com/Colythme/p/10109277.html
Copyright © 2011-2022 走看看