poj 3415 Common Substrings - 后缀数组 - 二分答案 - 单调栈

题目传送门

  传送点I

  传送点II

题目大意

  给定串$A, B$,求$A$和$B$长度大于等于$k$的公共子串的数量。

  根据常用套路,用一个奇怪的字符把$A$,$B$连接起来,然后二分答案,然后按mid分组。

  分完组考虑如何统计每一组的贡献。

  对于每一组内每一对$(A_i , B_j)$考虑拆成两部分:

  • $rank(A_i) < rank(B_j)$
  • $rank(A_i) > rank(B_j)$

  然后就可以从小到大枚举每一个串,然后考虑前面的$A_i$或$B_j$的贡献。

  显然这个贡献从当前串的前一个串往前走单调不增,然后就拿个单调栈维护就完了。

Code

  1 /**
  2  * poj
  3  * Problem#3415
  4  * Accepted
  5  * Time: 1110ms
  6  * Memory: 10232k
  7  */
  8 #include <iostream>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cstdio>
 12 #ifndef WIN32
 13 #define Auto "%lld"
 14 #else
 15 #define Auto "%I64d"
 16 #endif
 17 using namespace std;
 18 typedef bool boolean;
 19 #define ll long long
 20 
 21 #define pii pair<int, int>
 22 #define fi first
 23 #define sc second
 24 
 25 const int N = 2e5 + 5;
 26 
 27 typedef class Pair3 {
 28     public:
 29         int x, y, id;
 30 
 31         Pair3() {    }
 32         Pair3(int x, int y, int id):x(x), y(y), id(id) {    }
 33 }Pair3;
 34 
 35 typedef class SuffixArray {
 36     protected: 
 37         Pair3 T1[N], T2[N];
 38         int cnt[N];
 39 
 40     public:
 41         int n;
 42         char *str;
 43         int sa[N], rk[N], hei[N];
 44 
 45         void set(int n, char* str) {
 46             this->n = n;
 47             this->str = str;
 48             memset(sa, 0, sizeof(sa));
 49             memset(rk, 0, sizeof(rk));
 50             memset(hei, 0, sizeof(hei));
 51         }
 52 
 53         void radix_sort(Pair3* x, Pair3* y) {
 54             int m = max(n, 256);
 55             memset(cnt, 0, sizeof(int) * m);
 56             for (int i = 0; i < n; i++)
 57                 cnt[x[i].y]++;
 58             for (int i = 1; i < m; i++)
 59                 cnt[i] += cnt[i - 1];
 60             for (int i = 0; i < n; i++)
 61                 y[--cnt[x[i].y]] = x[i];
 62 
 63             memset(cnt, 0, sizeof(int) * m);
 64             for (int i = 0; i < n; i++)
 65                 cnt[y[i].x]++;
 66             for (int i = 1; i < m; i++)
 67                 cnt[i] += cnt[i - 1];
 68             for (int i = n - 1; ~i; i--)
 69                 x[--cnt[y[i].x]] = y[i];
 70         }
 71 
 72         void build() {
 73             for (int i = 0; i < n; i++)
 74                 rk[i] = str[i];
 75             for (int k = 1; k < n; k <<= 1) {
 76                 for (int i = 0; i + k < n; i++)
 77                     T1[i] = Pair3(rk[i], rk[i + k], i);
 78                 for (int i = n - k; i < n; i++)
 79                     T1[i] = Pair3(rk[i], 0, i);
 80                 radix_sort(T1, T2);
 81                 int diff = 0;
 82                 rk[T1[0].id] = 0;
 83                 for (int i = 1; i < n; i++)
 84                     rk[T1[i].id] = (T1[i].x == T1[i - 1].x && T1[i].y == T1[i - 1].y) ? (diff) : (++diff);
 85                 if (diff == n - 1)
 86                     break;
 87             }
 88             for (int i = 0; i < n; i++)
 89                 sa[rk[i]] = i;
 90         }
 91 
 92         void get_height() {
 93             for (int i = 0, j, k = 0; i < n; i++, (k) ? (k--) : (0)) {
 94                 if (rk[i]) {
 95                     j = sa[rk[i] - 1];
 96                     while (i + k < n && j + k < n && str[i + k] == str[j + k])    k++;
 97                     hei[rk[i]] = k;
 98                 }
 99             }        
100         }
101 
102         const int& operator [] (int p) {
103             return sa[p];
104         }
105 
106         const int& operator () (int p) {
107             return hei[p];
108         }
109 }SuffixArray;
110 
111 int K;
112 int n, m;
113 char S[N];
114 SuffixArray sa;
115 
116 inline boolean init() {
117     scanf("%d", &K);
118     if (!(K--))
119         return false;
120     scanf("%s", S);
121     n = strlen(S);
122     S[n] = '#';
123     scanf("%s", S + n + 1);
124     m = strlen(S + n + 1);
125     n += m + 1;
126     sa.set(n, S);
127     return true;
128 }
129 
130 ll res = 0, sum;
131 int tp = 0;
132 pii st[N];
133 inline void solve(int L, int R) {    // Calculate the s_i (i \in [L, R))
134     if (R - L < 2)
135         return ;
136     tp = sum = 0;
137     for (int i = L, sg; i < R - 1; i++) {
138         sg = (sa[i] < n - m - 1); 
139         if (!sg)
140             res += sum;
141         while (tp && st[tp].fi >= sa(i + 1))
142             sg += st[tp].sc, sum -= st[tp].sc * 1ll * (st[tp].fi - K), tp--;
143         sum += (sa(i + 1) - K) * 1ll * sg;
144         st[++tp] = pii(sa(i + 1), sg);
145     }
146     if (!(sa[R - 1] < n - m - 1))
147         res += sum;
148 
149     tp = sum = 0;
150     for (int i = L, sg; i < R - 1; i++) {
151         sg = !(sa[i] < n - m - 1);
152         if (!sg)
153             res += sum; 
154         while (tp && st[tp].fi >= sa(i + 1))
155             sg += st[tp].sc, sum -= st[tp].sc * 1ll * (st[tp].fi - K), tp--;
156         sum += (sa(i + 1) - K) * 1ll * sg;
157         st[++tp] = pii(sa(i + 1), sg);
158     }
159     if (sa[R - 1] < n - m - 1)
160         res += sum;
161 }
162 
163 inline void solve() {
164     res = 0;
165     sa.build();
166     sa.get_height();
167     
168     int lst = 0;
169     for (int i = 0; i < n; i++)
170         if (sa(i) < K + 1)
171             solve(lst, i), lst = i;
172     solve(lst, n);
173     printf(Auto"\n", res);
174 }
175 
176 int main() {
177     while (init())
178         solve();    
179     return 0;
180 }
posted @ 2018-10-09 21:17 阿波罗2003 阅读(...) 评论(...) 编辑 收藏