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

    题面:洛谷

    题解:

      因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献。

      所以子串这个限制相当于是没有的。

      所以我们只需要对于每个位置i求出f[i]表示以i为开头的形如BB这样的串的个数,g[i]表示以i为结尾的形如AA这样的串的个数即可。

      考虑分别处理这2个数组。

      我们可以枚举AA(BB)这样的串中A(B)的长度l,然后把原串每l个字符放在一个块中,在考虑统计答案。

      先考虑这样一个问题:

        假如固定一个串的结尾,再枚举这个串A的长度,怎样可以判断是否合法?

        实际上我们只需要判断我们假定的这个AA串的开头和中间位置(结尾向前走A的长度)的LCP是否可以覆盖开头到中间即可。

      然后如果我们已经把原串对于当前枚举的长度l分成了很多块,其实我们就已经可以对与每个块的开头结尾所代表的点对(i, j)判断是否可以产生贡献了。

      但是怎么统计 其他没有刚好对应在某个块的开头结尾的点对 的贡献呢?

      表示并没有想出来,,,但是感觉有个blog写的很好,,,

      推荐一下:[BZOJ]4650 优秀的拆分(Noi2016)

      以后彻底搞懂了再来填坑吧。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 301000
      5 #define ac 602000
      6 #define LL long long
      7 #define rev reverse
      8 #define mem(x) memset(x, 0, sizeof(x))
      9 
     10 int T, n, m;
     11 int h[ac], sa[ac], p1[ac], p2[ac], b[ac], d[ac];
     12 int rk[ac], p[AC], t[AC], rk1[ac];
     13 int st1[AC][19], st2[AC][19];
     14 int f[AC], g[AC];
     15 LL ans;
     16 char s[AC];
     17 
     18 void init()
     19 {
     20     for(R i = 1; i <= n; i ++) f[i] = g[i] = rk[i] = 0;//因为有多组数据,所以要全部清空
     21 }//mem这么多次还不如for
     22 
     23 inline void upmax(int &a, int b){
     24     if(b > a) a = b;
     25 }
     26 
     27 inline int Min(int a, int b){
     28     return (a < b) ? a : b;
     29 }
     30 
     31 void pre()
     32 {
     33     scanf("%s", s + 1), n = strlen(s + 1), m = 127;
     34 }
     35 
     36 void ssort()
     37 {
     38     for(R i = 1; i <= n; i ++) ++ d[p2[i]];
     39     for(R i = 1; i <= m; i ++) d[i] += d[i - 1];
     40     for(R i = 1; i <= n; i ++) b[d[p2[i]] --] = i;//给i分配d[p2[i]]的排名
     41     for(R i = 0; i <= m; i ++) d[i] = 0;
     42 
     43     for(R i = 1; i <= n; i ++) ++ d[p1[i]];
     44     for(R i = 1; i <= m; i ++) d[i] += d[i - 1];
     45     for(R i = n; i; -- i) sa[d[p1[b[i]]] --] = b[i];//给b[i]分配d[p1[b[i]]]的排名
     46     for(R i = 0; i <= m; i ++) d[i] = 0;    
     47 }
     48 
     49 void get_sa()
     50 {
     51     for(R i = 1; i <= n; i ++) sa[i] = i, rk[i] = s[i];//初始化
     52     m = 127;//这个也要重置
     53     for(R k = 1; k <= n; k <<= 1)
     54     {
     55         for(R i = 1; i <= n; i ++) p1[i] = rk[i], p2[i] = rk[i + k];
     56         ssort();
     57         int tmp = 1; 
     58         rk[sa[1]] = 1;        
     59         for(R i = 2; i <= n; i ++)
     60             rk[sa[i]] = (p1[sa[i]] == p1[sa[i - 1]] && p2[sa[i]] == p2[sa[i - 1]]) ? tmp : ++ tmp;
     61         if(tmp >= n) break;
     62         m = tmp;//忘了,,,
     63     }
     64 }
     65 
     66 void build()//获取h数组
     67 {
     68     //memset(h, 0, sizeof(h));
     69     for(R i = 1, k = 0; i <= n; i ++)
     70     {
     71         if(k) -- k;
     72         int j = sa[rk[i] - 1];
     73         while(s[i + k] == s[j + k]) ++ k;
     74         h[rk[i]] = k;
     75     }
     76 }
     77 
     78 #define st st1
     79 void build1()//建st1(维护LCP)
     80 {
     81     int tmp = 1, cnt = 0;
     82     memcpy(rk1, rk, sizeof(rk));
     83     for(R i = 1; i <= n; i ++)
     84     {
     85         st[i][0] = h[i];
     86         if(i == tmp << 1) tmp <<= 1, ++ cnt;
     87         p[i] = tmp, t[i] = cnt;
     88     }
     89 }
     90 #undef st
     91 
     92 void build2()//建st2(维护LCS)改成st1, st2一起建了。。。。
     93 {
     94     for(R i = 1; i <= n; i ++) st2[i][0] = h[i];
     95     int tmp = 1;
     96     for(R i = 1; i <= 18; i ++)
     97     {
     98         for(R j = 1; j <= n; j ++)
     99         {
    100             st1[j][i] = Min(st1[j][i - 1], st1[j + tmp][i - 1]);
    101             st2[j][i] = Min(st2[j][i - 1], st2[j + tmp][i - 1]);
    102         }
    103         tmp <<= 1;
    104     }
    105 }
    106 
    107 inline void swap(int &l, int &r)
    108 {
    109     int x = l;
    110     l = r, r = x;
    111 }
    112 
    113 int get1(int l, int r)//查询串l和串r的LCP
    114 {
    115     l = rk1[l], r = rk1[r];
    116     if(l > r) swap(l, r);
    117     ++ l;
    118     int len = r - l + 1;
    119     return Min(st1[l][t[len]], st1[r - p[len] + 1][t[len]]);
    120 }
    121 
    122 int get2(int l, int r)//查询串l和串r的LCS
    123 {//因为是翻转过来求的,所以查询要翻转一下
    124     l = n - l + 1, r = n - r + 1;
    125     l = rk[l], r = rk[r];
    126     if(l > r) swap(l, r);
    127     ++ l;
    128     int len = r - l + 1;
    129     return Min(st2[l][t[len]], st2[r - p[len] + 1][t[len]]);
    130 }
    131 
    132 void get()
    133 {
    134     int lim = n << 1;
    135     for(R k = 1; k < lim; k ++)//枚举A的长度
    136     {
    137         int maxn = 0, maxn2 = 0;
    138         for(R i = 1; i <= n; i += k)
    139         {
    140             int j = i + k;//j为下一段开头        
    141             if(j > n) break;
    142             if(i > maxn)
    143             {
    144                 int lcp = get1(i, j), lcs = get2(i, j);
    145                 maxn = i + lcp - 1; 
    146                 int l = i - lcs + 1, r = j + lcp - 2 * k;
    147                 if(lcp + lcs > k) ++ f[l], -- f[r + 1];
    148             }
    149             if(i > maxn2)
    150             {
    151                 int lcp = get2(n - i + 1, n - j + 1), lcs = get1(n - i + 1, n - j + 1);
    152                 maxn2 = i + lcp - 1; 
    153                 int l = i - lcs + 1, r = j + lcp - 2 * k;
    154                 if(lcp + lcs > k) ++ g[l], -- g[r + 1];
    155             }
    156         }    
    157     }
    158     for(R i = 1; i <= n; i ++) f[i] += f[i - 1], g[i] += g[i - 1];
    159     rev(g + 1, g + n + 1);
    160 }
    161 
    162 void work()
    163 {
    164     ans = 0;//f是开头
    165     for(R i = 1; i <= n; i += 2) 
    166         ans += 1LL * f[i] * g[i - 1] + ((i + 1 > n) ? 0 : 1LL * f[i + 1] * g[i]);
    167     printf("%lld
    ", ans);
    168 }
    169 
    170 int main()
    171 {
    172 //    freopen("in.in", "r", stdin);
    173     scanf("%d", &T);
    174     while(T --)
    175     {
    176         init();
    177         pre();
    178         get_sa();
    179         build();
    180         build1();//建st(维护LCP)
    181         rev(s + 1, s + n + 1);//翻转
    182     //    memset(rk, 0, sizeof(rk));//因为对于单组数据而言,长度不变,所以rk不必再次清空
    183         get_sa();
    184         build();
    185         build2();//建st2(维护LCS)
    186         get();
    187         work();
    188     }
    189 //    fclose(stdin);
    190     return 0;
    191 }
    View Code
  • 相关阅读:
    ABAP 程序中的类 沧海
    ABAP类的方法(转载) 沧海
    More than 100 ABAP Interview Faq's(2) 沧海
    SAP and ABAP Memory总结 沧海
    ABAP Frequently Asked Question 沧海
    ABAP System Reports(Additional functions) 沧海
    ABAP Questions Commonly Asked 1 沧海
    ABAP Tips and Tricks 沧海
    ABAP System Fields 沧海
    ABAP 面试问题及答案(一):数据库更新及更改 SAP Standard (转) 沧海
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10067865.html
Copyright © 2011-2022 走看看