poj 3415

Common Substrings

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 7605   Accepted: 2524

Description

A substring of a string T is defined as:

T(i, k)=TiTi+1...Ti+k-1, 1≤ii+k-1≤|T|.

Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):

S = {(i, j, k) | kK, A(i, k)=B(j, k)}.

You are to give the value of |S| for specific A, B and K.

Input

The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.

1 ≤ |A|, |B| ≤ 105
1 ≤ Kmin{|A|, |B|}
Characters of A and B are all Latin letters.

Output

For each case, output an integer |S|.

Sample Input

2
aababaa
abaabaa
1
xx
xx
0

Sample Output

22 5

题意:

给出两个串,问这两个串的所有的子串中(重复出现的,只要是位置不同就算两个子串),长度大于等于k的公共子串有多少个。

思路:

这个也是后缀自动机的比较好的题目.....

用一个串构建好后缀自动机,然后我们在这个串上面跑另外一个串,我们在这里应用上之前的spoj1811的匹配个数....

那么这样的串出现了多少次呢?....

就是spoj8222中的那个迭代更新的字串表示这个长度的子串出现了多少次的Right数组.....

我们这个东西就出现了 cnt * Right 次...真是太神奇了.....

  1 #include<cstdlib>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #ifdef WIN32
  6 #define fmt64 "%I64d"
  7 #else
  8 #define fmt64 "%lld"
  9 #endif
 10 using namespace std;
 11 const int maxn = (int)2.5e5,sigma = 26;
 12 char str[maxn];
 13 int k;
 14 int cmp(int, int);
 15 struct Sam{
 16     int ch[maxn][sigma << 1],par[maxn],stp[maxn],right[maxn],times[maxn],id[maxn];
 17     int sz,last;
 18     int idx(char x){
 19         if(‘a‘ <= x && x <= ‘z‘) return x - ‘a‘;
 20         else return x - ‘A‘ + 26;
 21     }
 22     void init(){
 23         for(int i = 1; i <= sz; ++i){
 24             memset(ch[i],0,sizeof(ch[i]));
 25             right[i] = times[i] = par[i] = stp[i] = 0;
 26         }
 27         sz = last = 1;
 28     }
 29     void add(int c){
 30         stp[++sz] = stp[last] + 1;
 31         int p = last, np = sz;
 32         for(; !ch[p][c]; p = par[p]) ch[p][c] = np;
 33         if(!p) par[np] = 1;
 34         else{
 35             int q = ch[p][c];
 36             if(stp[q] != stp[p] + 1){
 37                 stp[++sz] = stp[p] + 1;
 38                 int nq = sz;
 39                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
 40                 par[nq] = par[q];
 41                 par[q] = par[np] = nq;
 42                 for(; ch[p][c] == q; p = par[p]) ch[p][c] = nq;
 43             }
 44             else par[np] = q;
 45         }
 46         last = np;
 47     }
 48     void ins(char *pt){
 49         int i;
 50         init();
 51         for(i = 0; pt[i]; ++i) add(idx(pt[i]));
 52     }
 53     void prep(char *pt){
 54         int i,x = 1;
 55         for(i = 1; i <= sz; ++i) id[i] = i;
 56         sort(id + 1, id + sz + 1, cmp);
 57         for(i = 0; pt[i]; ++i){
 58             x = ch[x][idx(pt[i])];
 59             ++right[x];
 60         }
 61         for(i = 1; i <= sz; ++i)
 62             if(par[id[i]]) right[par[id[i]]] += right[id[i]];
 63     }
 64     void comp(char *pt){
 65         int i,x = 1,match = 0;
 66         long long ans = 0;
 67         for(i = 0; pt[i]; ++i){
 68             if(ch[x][idx(pt[i])]){
 69                 x = ch[x][idx(pt[i])];
 70                 match++;
 71             }
 72             else{
 73                 while(x && !ch[x][idx(pt[i])]) x = par[x];
 74                 if(!x) x = 1, match = 0;
 75                 else match = stp[x] + 1, x = ch[x][idx(pt[i])];
 76             }
 77             if(match >= k){
 78                 ans += (long long)(match - max(k, stp[par[x]] + 1) + 1) * right[x];
 79                 if(par[x] && k <= stp[par[x]]) times[par[x]]++;
 80             }
 81         }
 82         for(i = 1; i <= sz; ++i){
 83             int t = id[i];
 84             ans += (long long)times[t] * right[t] * (stp[t] - max(k, stp[par[t]] + 1) + 1);
 85             if(par[t] && k <= stp[par[t]]) times[par[t]] += times[t];
 86         }
 87         printf(fmt64"\n",ans);
 88     }
 89 }sam;
 90 int cmp(int x,int y){
 91     return sam.stp[x] > sam.stp[y];
 92 }
 93 int main()
 94 {
 95     freopen("csb.in","r",stdin);
 96     freopen("csb.out","w",stdout);
 97     while(scanf("%d\n",&k) != EOF,k){
 98         scanf("%s\n",str);
 99         sam.ins(str);
100         sam.prep(str);
101         scanf("%s\n",str);
102         sam.comp(str);
103     }
104     return 0;
105 } 

时间: 2024-11-11 08:26:11

poj 3415的相关文章

POJ 3415 Common Substrings (求长度不小于k的公共子串的个数)

Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10002   Accepted: 3302 Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given two strings A, B and one integer K, we define S,

poj 3415 后缀数组分组+排序+并查集

Source Code Problem: 3415   User: wangyucheng Memory: 16492K   Time: 704MS Language: C++   Result: Accepted Source Code #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define N 510000

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 Ran

POJ 3415 Common Substrings(后缀数组+单调栈)

[题目链接] http://poj.org/problem?id=3415 [题目大意] 求出两个字符串长度大于k的公共子串的数目. [题解] 首先,很容易想到O(n2)的算法,将A串和B串加拼接符相连, 做一遍后缀数组,把分别属于A和B的所有后缀匹配,LCP-k+1就是对答案的贡献, 但是在这个基础上该如何优化呢. 我们可以发现按照sa的顺序下来,每个后缀和前面的串的LCP就是区间LCP的最小值, 那么我们维护一个单调栈,将所有单调递减的LCP值合并, 保存数量和长度,对每个属于B串的后缀更新

POJ 3415 Common Substrings

Common Substrings Time Limit: 5000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 341564-bit integer IO format: %lld      Java class name: Main A substring of a string T is defined as: \[T(i, k)=T_iT_{i+1}\dots T_{i+k-1}, 1\

【POJ 3415】Common Substrings 长度不小于k的公共子串的个数

长度不小于k的公共子串的个数,论文里有题解,卡了一上午,因为sum没开long long!!! 没开long long毁一生again--- 以后应该早看POJ里的Discuss啊QAQ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 200003; int t1[N], t2[N], c[

字符串(后缀数组):POJ 3415 Common Substrings

Common Substrings Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given two strings A, B and one integer K, we define S, a set of triples (i, j, k): S = {(i, j, k) | k≥K, A(i, k)=B(j, k)}. You are to give

POJ - 3415 Common Substrings 后缀数组+单调栈

一般遇到多串问题,就用不同的符号把他们接起来,当成一个串来处理. 如A串是"aaaba",B串是"abaa". 把height数组按照不小于K分组,假设K = 2.从前向后扫描,对于每一组中的每个B,考虑前面A对其的贡献. 可以用栈来维护A的值.当要入栈的height值大于栈顶的值,统计得到的子串的数目 (+= height[i]-K+1). 如果小于,总和减去多加的部分,pop到小于height[i]为止,再入栈算贡献.

POJ 3415 Common Substrings ——后缀数组

[题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue>