POJ 3415 后缀数组+单调栈

链接:

http://poj.org/problem?id=3415

题意:

统计A和B长度不小于K的公共子串个数。

题解:

将A和B拼接后,利用单调栈累计分属两者的后缀对应的LCP-K+1即为答案

代码:

 31 int n, k;
 32 int Rank[MAXN], tmp[MAXN];
 33 int sa[MAXN], lcp[MAXN];
 34 
 35 bool compare_sa(int i, int j) {
 36     if (Rank[i] != Rank[j]) return Rank[i] < Rank[j];
 37     else {
 38         int ri = i + k <= n ? Rank[i + k] : -1;
 39         int rj = j + k <= n ? Rank[j + k] : -1;
 40         return ri < rj;
 41     }
 42 }
 43 
 44 void construct_sa(string S, int *sa) {
 45     n = S.length();
 46     for (int i = 0; i <= n; i++) {
 47         sa[i] = i;
 48         Rank[i] = i < n ? S[i] : -1;
 49     }
 50     for (k = 1; k <= n; k *= 2) {
 51         sort(sa, sa + n + 1, compare_sa);
 52         tmp[sa[0]] = 0;
 53         for (int i = 1; i <= n; i++)
 54             tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
 55         for (int i = 0; i <= n; i++) Rank[i] = tmp[i];
 56     }
 57 }
 58 
 59 void construct_lcp(string S, int *sa, int *lcp) {
 60     int n = S.length();
 61     for (int i = 0; i <= n; i++) Rank[sa[i]] = i;
 62     int h = 0;
 63     lcp[0] = 0;
 64     for (int i = 0; i < n; i++) {
 65         int j = sa[Rank[i] - 1];
 66         if (h > 0) h--;
 67         for (; j + h < n && i + h < n; h++)
 68             if (S[j + h] != S[i + h]) break;
 69         lcp[Rank[i] - 1] = h;
 70     }
 71 }
 72 
 73 PII st[MAXN];
 74 ll contribution, top;
 75 
 76 ll solve(int k, int n1, bool is_s1) {
 77     ll ans = 0;
 78     rep(i, 0, n) {
 79         if (lcp[i] < k) {
 80             top = contribution = 0;
 81             continue;
 82         }
 83         int size = 0;
 84         if (is_s1 && sa[i] < n1 || !is_s1 && sa[i] > n1) {
 85             size++;
 86             contribution += lcp[i] - k + 1;
 87         }
 88         while (top > 0 && st[top].first >= lcp[i]) {
 89             contribution -= st[top].second*(st[top].first - lcp[i]);
 90             size += st[top].second;
 91             top--;
 92         }
 93         st[++top] = mp(lcp[i], size);
 94         if (is_s1 && sa[i + 1] > n1 || !is_s1 && sa[i + 1] < n1) ans += contribution;
 95     }
 96     return ans;
 97 }
 98 
 99 int main() {
100     ios::sync_with_stdio(false), cin.tie(0);
101     int k;
102     while (cin >> k, k) {
103         string a, b;
104         cin >> a >> b;
105         int n1 = a.length();
106         string s = a + '$' + b;
107         construct_sa(s, sa);
108         construct_lcp(s, sa, lcp);
109         cout << solve(k, n1, true) + solve(k, n1, false) << endl;
110     }
111     return 0;
112 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值