zoukankan      html  css  js  c++  java
  • [NOI2016]优秀的拆分

    题意

    一串字符串的子串能够被拆分成不重叠的$AABB$($A, B$为该子串的子串)的方案数

    题解

    考虑对子串进行隔离处理,枚举隔离长度$l$

    那么在此隔离长度下若存在子串满足$AABB$,那么它必定横跨两个隔离点,那么此时求出每相邻两个隔离点的最长公共前缀$x$和最长公共后缀$y$(跑两遍$SA$求),那么若$x + y >= l$,那么必定可以构成$AABB$的子串(画下图就知道了),那么再统计数量,找到满足该条件的起始位置和终止位置,用差分就好了

    代码

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <cmath>
      6 #include <vector>
      7 
      8 using namespace std;
      9 
     10 typedef long long LL;
     11 
     12 const int MAXN = 3e04 + 10;
     13 
     14 int T;
     15 
     16 int N;
     17 
     18 struct Suffix_Array {
     19     char Str[MAXN];
     20     int M = 122;
     21     int SA[MAXN]= {0};
     22     int Fir[MAXN]= {0}, Srk[MAXN]= {0};
     23     int buck[MAXN]= {0};
     24     void SA_Requirement () {
     25         M = 122;
     26         for (int i = 1; i <= M; i ++)
     27             buck[i] = 0;
     28         for (int i = 1; i <= N; i ++)
     29             buck[Fir[i] = Str[i]] ++;
     30         for (int i = 2; i <= M; i ++)
     31             buck[i] += buck[i - 1];
     32         for (int i = N; i >= 1; i --)
     33             SA[buck[Fir[i]] --] = i;
     34         for (int k = 1; k <= N; k <<= 1) {
     35             int p = 0;
     36             for (int i = N - k + 1; i <= N; i ++)
     37                 Srk[++ p] = i;
     38             for (int i = 1; i <= N; i ++)
     39                 if (SA[i] > k)
     40                     Srk[++ p] = SA[i] - k;
     41             for (int i = 1; i <= M; i ++)
     42                 buck[i] = 0;
     43             for (int i = 1; i <= N; i ++)
     44                 buck[Fir[i]] ++;
     45             for (int i = 2; i <= M; i ++)
     46                 buck[i] += buck[i - 1];
     47             for (int i = N; i >= 1; i --)
     48                 SA[buck[Fir[Srk[i]]] --] = Srk[i], Srk[i] = 0;
     49             swap (Fir, Srk);
     50             Fir[SA[1]] = 1, p = 1;
     51             for (int i = 2; i <= N; i ++)
     52                 Fir[SA[i]] = (Srk[SA[i]] == Srk[SA[i - 1]] && Srk[SA[i] + k] == Srk[SA[i - 1] + k]) ? p : ++ p;
     53             if (p == N)
     54                 break;
     55             M = p;
     56         }
     57     }
     58     int Rank[MAXN]= {0};
     59     int Height[MAXN]= {0};
     60     void Height_Array () {
     61         for (int i = 1; i <= N; i ++)
     62             Rank[SA[i]] = i;
     63         int k = 0;
     64         for (int i = 1; i <= N; i ++) {
     65             if (k)
     66                 k --;
     67             int j = SA[Rank[i] - 1];
     68             while (j + k <= N && i + k <= N && Str[j + k] == Str[i + k])
     69                 k ++;
     70             Height[Rank[i]] = k;
     71         }
     72     }
     73 
     74     int ST[MAXN][20];
     75     void RMQ () {
     76         for (int i = 1; i <= N; i ++)
     77             ST[i][0] = Height[i];
     78         for (int j = 1; j <= 18; j ++)
     79             for (int i = 1; i + (1 << j) - 1 <= N; i ++)
     80                 ST[i][j] = min (ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
     81     }
     82     int Query (int l, int r) {
     83         l ++;
     84         int k = log2 (r - l + 1);
     85         return min (ST[l][k], ST[r - (1 << k) + 1][k]);
     86     }
     87     int LCP (int x, int y) {
     88         if (Rank[x] > Rank[y])
     89             swap (x, y);
     90         return Query (Rank[x], Rank[y]);
     91     }
     92     void init () {
     93         memset (SA, 0, sizeof (SA));
     94         memset (Height, 0, sizeof (Height));
     95         memset (Rank, 0, sizeof (Rank));
     96         memset (Fir, 0, sizeof (Fir));
     97         memset (Srk, 0, sizeof (Srk));
     98     }
     99 } For, Rev;
    100 
    101 int endwith[MAXN]= {0}, startwith[MAXN]= {0};
    102 
    103 int main () {
    104     scanf ("%d", & T);
    105     for (int Case = 1; Case <= T; Case ++) {
    106         memset (endwith, 0, sizeof (endwith));
    107         memset (startwith, 0, sizeof (startwith));
    108         For.init (), Rev.init ();
    109         scanf ("%s", For.Str + 1);
    110         N = strlen (For.Str + 1);
    111         for (int i = 1; i <= N; i ++)
    112             Rev.Str[i] = For.Str[N - i + 1];
    113         For.SA_Requirement (), For.Height_Array (), For.RMQ ();
    114         Rev.SA_Requirement (), Rev.Height_Array (), Rev.RMQ ();
    115         LL ans = 0;
    116         for (int l = 1; l <= (N >> 1); l ++)
    117             for (int i = l, j = (l << 1); j <= N; i += l, j += l) {
    118                 int lcpfor = min (For.LCP (i, j), l);
    119                 int lcprev = min (Rev.LCP (N - j + 1, N - i + 1), l);
    120                 if (lcpfor + lcprev - 1 >= l) {
    121                     endwith[j + l - lcprev] ++;
    122                     endwith[j + lcpfor] --;
    123                     startwith[i - lcprev + 1] ++;
    124                     startwith[i - (l - lcpfor - 1)] --;
    125                 }
    126             }
    127         for (int i = 1; i <= N; i ++) {
    128             endwith[i] += endwith[i - 1];
    129             startwith[i] += startwith[i - 1];
    130         }
    131         for (int i = 1; i <= N; i ++)
    132             ans += (LL) endwith[i] * startwith[i + 1];
    133         printf ("%lld
    ", ans);
    134     }
    135 
    136     return 0;
    137 }
    138 
    139 /*
    140 4
    141 aabbbb
    142 cccccc
    143 aabaabaabaa
    144 bbaabaababaaba
    145 */
    146 
    147 /*
    148 1
    149 aabbbb
    150 */
    151 
    152 /*
    153 10
    154 zzzzzzzzzzzzzzzzzzzzzzzzzzz
    155 icicicicicicicicicicic
    156 saasaasaasaasaasaasaa
    157 znunznunznunznunznun
    158 ttfhhttfhhttfhhttfhhttfhh
    159 fqxqblfqxqblfqxqblfqxqblfqxqbl
    160 xxpruxxpruxxpruxxpru
    161 mpheqsmpheqsmpheqsmpheqs
    162 ptvbemqptvbemqptvbemqptvbemq
    163 nxykqknxykqknxykqknxykqk
    164 */
    165 
    166 /*
    167 1
    168 mpheqsmpheqsmpheqsmpheqs
    169 */
    View Code
  • 相关阅读:
    哈夫曼树
    粒子群算法(1)----粒子群算法简单介绍
    白话经典算法系列之七 堆与堆排序
    UVa 11879
    有计划,公司运行——写到犹豫大三女生
    _00013 一致性哈希算法 Consistent Hashing 新的讨论,并出现相应的解决
    s3c2440的A/D转换应用
    iSwifting如何发送照片社区
    【Android开发经验】使用反射,得到的类的字段、方法、并实现了简单的调用
    于Unity3D动态创建对象和创建Prefab三种方式的原型对象
  • 原文地址:https://www.cnblogs.com/Colythme/p/10081744.html
Copyright © 2011-2022 走看看