• BZOJ 3230: 相似子串


    3230: 相似子串

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1485  Solved: 361
    [Submit][Status][Discuss]

    Description

    Input

    输入第1行,包含3个整数N,Q。Q代表询问组数。
    第2行是字符串S。
    接下来Q行,每行两个整数i和j。(1≤i≤j)。

    Output

    输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。

    Sample Input

    5 3
    ababa
    3 5
    5 9
    8 10

    Sample Output

    18
    16
    -1

    HINT

    样例解释

    第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。

    第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。

    第3组询问:不存在第10个子串。输出-1。


    数据范围

    N≤100000,Q≤100000,字符串只由小写字母'a'~'z'组成

    Source

    [Submit][Status][Discuss]

    Source里说的十分清楚了,题目本身也很水。

    求出后缀数组,再把字符串reverse后求出“前缀数组”。

    通过后缀数组可以对子串按排名进行定位,然后查询正反LCP即可。

      1 #include <bits/stdc++.h>
      2 
      3 template <class T>
      4 T sqr(T x)
      5 {
      6     return x*x;
      7 }
      8 
      9 typedef long long longint;
     10 
     11 const int maxn = 100005;
     12 const longint inf = 1e9;
     13 
     14 int n, m; 
     15 char s[maxn];
     16 longint g[maxn];
     17 longint pre[maxn];
     18 
     19 class SuffixArray
     20 {
     21 public:
     22     int sa[maxn], rk[maxn], ht[maxn];
     23 
     24     inline void init(void)
     25     {
     26         memset(ca, 0, sizeof(ca));
     27 
     28         for (int i = 1; i <= n; ++i)
     29             ++ca[s[i]];
     30 
     31         for (int i = 1; i <= 300; ++i)
     32             ca[i] += ca[i - 1];
     33 
     34         for (int i = n; i >= 1; --i)
     35             sa[ca[s[i]]--] = i;
     36 
     37         rk[sa[1]] = 1;
     38 
     39         for (int i = 2; i <= n; ++i)
     40             rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]);
     41 
     42         for (int l = 1; rk[sa[n]] < n; l <<= 1)
     43         {
     44             memset(ca, 0, sizeof(ca));
     45             memset(cb, 0, sizeof(cb));
     46 
     47             for (int i = 1; i <= n; ++i)
     48             {
     49                 ++ca[wa[i] = rk[i]];
     50                 ++cb[wb[i] = i + l <= n ? rk[i + l] :0];
     51             }
     52             
     53             for (int i = 1; i <= n; ++i)
     54             {
     55                 ca[i] += ca[i - 1];
     56                 cb[i] += cb[i - 1];
     57             }
     58 
     59             for (int i = n; i >= 1; --i)
     60                 ta[cb[wb[i]]--] = i;
     61 
     62             for (int i = n; i >= 1; --i)
     63                 sa[ca[wa[ta[i]]]--] = ta[i];
     64 
     65             rk[sa[1]] = 1;
     66 
     67             for (int i = 2; i <= n; ++i)    
     68                 rk[sa[i]] = rk[sa[i - 1]] + (wa[sa[i]] != wa[sa[i - 1]] || wb[sa[i]] != wb[sa[i - 1]]);
     69         }
     70 
     71         for (int i = 1, j = 0; i <= n; ++i)
     72         {
     73             if (--j < 0)j = 0;
     74             while (s[i + j] == s[sa[rk[i] - 1] + j])++j;
     75             ht[rk[i]] = j;
     76         }
     77         
     78         build(1, 1, n);
     79     }
     80 
     81     inline int lcp(int a, int b)
     82     {
     83         a = rk[a];
     84         b = rk[b];
     85 
     86         if (a > b)
     87         {
     88             a ^= b;
     89             b ^= a;
     90             a ^= b;
     91         }
     92 
     93         return query(1, 1, n, a + 1, b);
     94     }
     95 private:
     96     void build(int t, int l, int r)
     97     {
     98         if (l == r)
     99             tr[t] = ht[l];
    100         else
    101         {
    102             int mid = (l + r) >> 1;
    103             build(t << 1, l, mid);
    104             build(t << 1 | 1, mid + 1, r);
    105             tr[t] = std::min(tr[t << 1], tr[t << 1 | 1]);
    106         }
    107     }
    108     
    109     int query(int t, int l, int r, int a, int b)
    110     {
    111         if (l == a && r == b)
    112             return tr[t];
    113         else
    114         {
    115             int mid = (l + r) >> 1;
    116             if (b <= mid)
    117                 return query(t << 1, l, mid, a, b);
    118             else if (a > mid)
    119                 return query(t << 1 | 1, mid + 1, r, a, b);
    120             else
    121                 return std::min(query(t << 1, l, mid, a, mid), query(t << 1 | 1, mid + 1, r, mid + 1, b));
    122         }
    123     }
    124     
    125     int ta[maxn], wa[maxn], wb[maxn], ca[maxn], cb[maxn], tr[maxn << 2];
    126 }A, B;
    127 
    128 signed main(void)
    129 {
    130     scanf("%d%d%s", &n, &m, s + 1); 
    131 
    132     g[0] = -1;
    133 
    134     for (int i = 1; i <= n; ++i)
    135         g[i] = g[i >> 1] + 1;
    136 
    137     A.init();
    138     std::reverse(s + 1, s + 1 +n);
    139     B.init();
    140 
    141     pre[0] = 0;
    142 
    143     for (int i = 1; i <= n; ++i)
    144         pre[i] = pre[i - 1] + n - A.sa[i] + 1 - A.ht[i];
    145         
    146     for (int i = 1; i <= m; ++i)
    147     {
    148         longint lt, rt; scanf("%lld%lld", &lt, &rt);
    149     
    150         if (lt > pre[n] || rt > pre[n])
    151             { puts("-1"); continue; }
    152         
    153         int id1, id2, a1, b1, a2, b2;
    154         
    155         id1 = std::lower_bound(pre + 1, pre + 1 + n, lt) - pre;
    156         id2 = std::lower_bound(pre + 1, pre + 1 + n, rt) - pre;
    157         
    158         a1 = A.sa[id1];
    159         a2 = A.sa[id2];
    160         
    161         b1 = a1 + A.ht[id1] - 1 + lt - pre[id1 - 1];
    162         b2 = a2 + A.ht[id2] - 1 + rt - pre[id2 - 1];
    163         
    164         longint ans = 0, tmp;
    165 
    166         tmp = a1 == a2 ? inf : A.lcp(a1, a2);
    167         tmp = std::min(tmp, (longint)std::min(b1 - a1 + 1, b2 - a2 + 1));
    168 
    169         ans += sqr(tmp);
    170 
    171         tmp = b1 == b2 ? inf : B.lcp(n - b1 + 1, n - b2 + 1);
    172         tmp = std::min(tmp, (longint)std::min(b1 - a1 + 1, b2 - a2 + 1));
    173 
    174         ans += sqr(tmp);
    175 
    176         printf("%lld
    ", ans);
    177     }
    178 }

    @Author: YouSiki

  • 相关阅读:
    简单记事本 V0.5
    一次对webplayer的嗅探
    引用的DLL不能调试的问题
    软件:让人越懒越好
    如何设置mysql远程访问
    ASP.NET基础培训 Cookie的正确利用
    Mysql中新建和调用存储过程
    CentOS下mysql的中文编码问题
    mysmall.ini、mymedium.ini、mylarge.ini、myhuge.ini文件的作用
    创建自定义线程池
  • 原文地址:https://www.cnblogs.com/yousiki/p/6209162.html
Copyright © 2020-2023  润新知