POJ 3415

Common Substrings
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 8358 Accepted: 2761

Description

A substring of a string T is defined as:

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

Given two strings AB and one integer K, we define S, a set of triples (ijk):

S = {( ijk) |  kKA( ik)= B( jk)}.

You are to give the value of |S| for specific AB 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 ≤ K ≤ min{|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

Source



题意:给出两个字符串SA, SB和一个数K,求两个字符串的长度不小于k的公共子串个数。


思路:两个字符串中间用一个没出现过的字符连接,之后求出height数组,根据K将后缀分组,对每一组判断每个后缀属于SA串还是SB串,对每个SA串,求前面的SB串与它的LCP长度,同样,对每个SB串,求前面的SA串与它的LCP长度。对于两个后缀,设它们的LCP值为L,则这两个后缀能产生L-K+1个公共字串。而求每个SA串与前面的SB串能产生多少公共子串可以用单调栈O(len)的实现:栈中维护每个后缀的height值,以及从起点扫描到该位置时,有多少个后缀的height值大于等于当前后缀的height值,于是每次扫描到一个后缀,将其加入单调栈中(需要弹出小于等于它的元素),计算该后缀的cnt值。



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <stack>

using namespace std;

#define INF 110000
#define N 201000
#define M 201000

int k, n, m, len1, len2;
char s[N];
int str[N], rank[N], sa[N], bucket[N], trank[N], sa2[N], height[N];

class Node
{
public:
    int val, cnt;
    Node(int _val, int _cnt)
    {
        val = _val;
        cnt = _cnt;
    }
};
stack<Node> sta;


int cmp(int p1, int p2, int len)
{
    return p1+len < n && p2+len < n && trank[p1] == trank[p2] && trank[p1+len] == trank[p2+len];
}

void getSa()
{
    for(int i = 0; i < m; i++) bucket[i] = 0;
    for(int i = 0; i < n; i++) bucket[rank[i] = str[i]]++;
    for(int i = 1; i < m; i++) bucket[i] += bucket[i-1];
    for(int i = n-1; i >= 0; i--) sa[--bucket[rank[i]]] = i;
    for(int j = 1, p = 0; p < n; j <<= 1, m = p)
    {
        p = 0;
        for(int i = n-j; i < n; i++) sa2[p++] = i;
        for(int i = 0; i < n; i++)
            if(sa[i] >= j) sa2[p++] = sa[i]-j;
        for(int i = 0; i < m; i++) bucket[i] = 0;
        for(int i = 0; i < n; i++) bucket[rank[i]]++;
        for(int i = 1; i < m; i++) bucket[i] += bucket[i-1];
        for(int i = n-1; i >= 0; i--) sa[--bucket[rank[sa2[i]]]] = sa2[i];
        for(int i = 0; i < n; i++) trank[i] = rank[i];
        p = 0; rank[sa[0]] = p++;
        for(int i = 1; i < n; i++)
            rank[sa[i]] = cmp(sa[i], sa[i-1], j) ? p-1 : p++;
    }
}
void getHeight()
{
    int h = 0;
    height[0] = 0;
    for(int i = 0; i < n; i++)
    {
        if(rank[i] == 0) continue;
        if(h) h--;
        int pre = sa[rank[i]-1];
        for(; pre+h < n && i+h < n && str[i+h] == str[pre+h]; h++);
        height[rank[i]] = h;
    }
}

inline int get(int pos)
{
    if(sa[pos] == len1) return 0;
    return sa[pos] < len1 ? 1 : 2;
}

long long cal(int l, int r, int flag)
{
    while(!sta.empty()) sta.pop();
    long long res = 0, sum = 0;
    if(get(l) != flag)
    {
        sta.push(Node(INF, 1));
        sum += INF-k+1;
    }
    for(int i = l+1; i <= r; i++)
    {
        int cnt = 0;
        while(!sta.empty() && sta.top().val >= height[i])
        {
            sum -= (sta.top().val-k+1)*sta.top().cnt;
            cnt += sta.top().cnt;
            sum += (height[i]-k+1)*sta.top().cnt;
            sta.pop();
        }
        if(cnt)
            sta.push(Node(height[i], cnt));
        if(get(i) != flag)
        {
            sum += INF-k+1;
            sta.push(Node(INF, 1));
        }

        if(get(i) == flag)
        {
            res += sum;
        }
    }
    return res;
}
int main()
{
    //freopen("C:\\Users\\zfh\\Desktop\\in.txt", "r", stdin);
    while(scanf("%d", &k) != -1 && k)
    {

        scanf(" %s", s);
        n = 0; m = 300;
        len1 = strlen(s);
        for(int i = 0; i < len1; i++) str[n++] = s[i];
        str[n++] = 0;
        scanf(" %s", s);
        len2 = strlen(s);
        for(int i = 0; i < len2; i++) str[n++] = s[i];
        str[n] = 1;

        getSa();
        getHeight();
        int sp = 0, tp = 0;
        long long ans = 0;
        for(int i = 0; i < n; i++)
        {
            if(height[i] >= k)
            {
                tp = i;
            }
            else
            {
                ans += cal(sp, tp, 1);
                ans += cal(sp, tp, 2);
                sp = tp = i;
            }
        }
        ans += cal(sp, tp, 1);
        ans += cal(sp, tp, 2);
        printf("%I64d\n", ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园失物招领系统管理系统按照操作主体分为管理员和用户。管理员的功能包括字典管理、论坛管理、公告信息管理、失物招领管理、失物认领管理、寻物启示管理、寻物认领管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 校园失物招领系统管理系统可以提高校园失物招领系统信息管理问题的解决效率,优化校园失物招领系统信息处理流程,保证校园失物招领系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 ,管理员权限操作的功能包括管理公告,管理校园失物招领系统信息,包括失物招领管理,培训管理,寻物启事管理,薪资管理等,可以管理公告。 失物招领管理界面,管理员在失物招领管理界面中可以对界面中显示,可以对失物招领信息的失物招领状态进行查看,可以添加新的失物招领信息等。寻物启事管理界面,管理员在寻物启事管理界面中查看寻物启事种类信息,寻物启事描述信息,新增寻物启事信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值