长度不小于k的公共子串个数

题目链接:https://cn.vjudge.net/contest/318888#problem/J

 

思路:

 

  1 #include <stdio.h>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <math.h>
  7 #include <queue>
  8 #include <set>
  9 
 10 #define INF 0x3f3f3f3f
 11 #define pii pair<int,int>
 12 #define LL long long
 13 using namespace std;
 14 typedef unsigned long long ull;
 15 const int MAXN = 2e5 + 10;
 16 int t;
 17 int wa[MAXN], wb[MAXN], wv[MAXN], ws_[MAXN];
 18 int sta[MAXN];
 19 int cnt[MAXN];
 20 void Suffix(int *r, int *sa, int n, int m)
 21 {
 22     int i, j, k, *x = wa, *y = wb, *t;
 23     for(i = 0; i < m; ++i) ws_[i] = 0;
 24     for(i = 0; i < n; ++i) ws_[x[i] = r[i]]++;
 25     for(i = 1; i < m; ++i) ws_[i] += ws_[i - 1];
 26     for(i = n - 1; i >= 0; --i) sa[--ws_[x[i]]] = i;
 27     for(j = 1, k = 1; k < n; j *= 2, m = k)
 28     {
 29         for(k = 0, i = n - j; i < n; ++i) y[k++] = i;
 30         for(i = 0; i < n; ++i) if(sa[i] >= j) y[k++] = sa[i] - j;
 31         for(i = 0; i < n; ++i) wv[i] = x[y[i]];
 32         for(i = 0; i < m; ++i) ws_[i] = 0;
 33         for(i = 0; i < n; ++i) ws_[wv[i]]++;
 34         for(i = 1; i < m; ++i) ws_[i] += ws_[i - 1];
 35         for(i = n - 1; i >= 0; --i) sa[--ws_[wv[i]]] = y[i];
 36         t = x;
 37         x = y;
 38         y = t;
 39         for(x[sa[0]] = 0, i = k = 1; i < n; ++i)
 40             x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j]) ? k - 1 : k++;
 41     }
 42 }
 43 int Rank[MAXN], height[MAXN], sa[MAXN], r[MAXN];
 44 char s[MAXN],ss[MAXN];
 45 int indexx[MAXN],vis[200];
 46 void calheight(int *r,int *sa,int n)
 47 {
 48     int i,j,k=0;
 49     for(i=1; i<=n; i++)Rank[sa[i]]=i;
 50     for(i=0; i<n; height[Rank[i++]]=k)
 51         for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
 52 }
 53 
 54 
 55 int main(){
 56     while (~scanf("%d",&t) && t){
 57         memset(r,0, sizeof(r));
 58         memset(sa,0, sizeof(sa));
 59         memset(Rank,0, sizeof(Rank));
 60         scanf("%s%s",s,ss);
 61         int len1 = strlen(s);
 62         int len2 = strlen(ss);
 63         s[len1] = '@';
 64         for (int i=0;i<len2;i++){
 65             s[len1+1+i] = ss[i];
 66         }
 67         s[len1+len2+1] = '\0';
 68         for (int i=0;i<len1+len2+1;i++){
 69             r[i] = s[i];
 70         }
 71         r[len1+len2+2] = 0;
 72         Suffix(r,sa,len1+len2+2,300);
 73         calheight(r,sa,len1+len2+1);
 74         LL sum = 0,ans = 0; //sum代表栈里面对答案的贡献值,cnt数组记录的是一个组内的后缀数
 75         int top = 0;
 76         for (int i=1;i<len1+len2+2;i++){  // 处理A和它前面B的公共前缀
 77             if (height[i]<t){
 78                 top = 0;
 79                 sum = 0;
 80                 continue;
 81             }
 82             int num = 0;
 83             while (top && height[i]<sta[top]){
 84                 sum -= (LL)(sta[top]-t+1)*cnt[top]; //在这儿比height[i]大的都要变成height[i],所以先减去先前加上去的
 85                 sum += (LL)(height[i]-t+1)*cnt[top]; //乘cnt[top]的原因是可能有多个合并成一个了,比如4,5,3,那么4和5都只能以3来计算
 86                 num += cnt[top]; //那么此时这三个可以合并在一起,cnt个数就是3,和就是3*3=9
 87                 top--;
 88             }
 89             sta[++top] = height[i];
 90             if (sa[i-1]>len1){
 91                 sum += (LL)(height[i]-t+1);
 92                 cnt[top]  = num+1;
 93             }
 94             else
 95                 cnt[top] = num;
 96             if (sa[i]<len1)
 97                 ans += sum;
 98         }
 99         sum = 0,top = 0; 
100 
101         for (int i=1;i<=len1+len2+2;i++){ //处理B和它前面的A的公共前缀
102             if (height[i]<t){
103                 top = 0;
104                 sum = 0;
105                 continue;
106             }
107             int num = 0;
108             while (top && height[i]<sta[top]){
109                 sum -= (LL)(sta[top]-t+1)*cnt[top]; 
110                 sum += (LL)(height[i]-t+1)*cnt[top]; 
111                 num += cnt[top];  
112                 top--;
113             }
114             sta[++top] = height[i];
115             if (sa[i-1]<len1){
116                 sum += (LL)(height[i]-t+1);
117                 cnt[top]  = num+1;
118             }
119             else
120                 cnt[top] = num;
121             if (sa[i]>len1)
122                 ans += sum;
123         }
124         printf("%lld\n",ans);
125     }
126     return 0;
127 }

 

posted @ 2019-08-13 01:07  _Ackerman  阅读(304)  评论(0编辑  收藏  举报