POJ 3729 Facer’s string (后缀数组)

题目大意:

串1中有多少个后缀和 串2中的某个后缀 的lcp 为 k

思路分析:

先找出 长度至少为k的对数有多少。

再找出 至少为k+1的有多少

然后相减。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#define maxn 110005
using namespace std;

int str[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;
void suffix(int m)
{
    int *x=t1,*y=t2;
    for(int i=0; i<m; i++)c[i]=0;
    for(int i=0; i<n; i++)c[x[i]=str[i]]++;
    for(int i=1; i<m; i++)c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int p=0;
        for(int i=n-k; i<n; i++)y[p++]=i;
        for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0; i<m; i++)c[i]=0;
        for(int i=0; i<n; i++)c[x[y[i]]]++;
        for(int i=0; i<m; i++)c[i]+=c[i-1];
        for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
int rank[maxn],height[maxn];
void getheight()
{
    int k=0;
    for(int i=0; i<n; i++)rank[sa[i]]=i;
    for(int i=0; i<n; i++)
    {
        if(k)k--;
        if(!rank[i])continue;
        int j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int tmp[50005];

int solve(int k,int nn)
{
    int ans=0;
    int res=0,ret=0;
    for(int i=1; i<n; i++)
    {
        if(height[i]<k)
        {
            if(ret)
                ans+=res;
            res=ret=0;
            if(sa[i]<nn)res++;
            else ret++;
        }
        else
        {
            if(sa[i]<nn)res++;
            else ret++;
        }
    }
    if(ret)ans+=res;
    return ans;
}
int main()
{
    int nn,mm,k;
    while(scanf("%d%d%d",&nn,&mm,&k)!=EOF)
    {
        int top=0;
        for(int i=1; i<=nn; i++)
        {
            scanf("%d",&tmp[i]);
            tmp[i]+=2;
            str[top++]=tmp[i];
        }
        str[top++]=1;

        for(int i=1; i<=mm; i++)
        {
            scanf("%d",&tmp[i]);
            tmp[i]+=2;
            str[top++]=tmp[i];
        }
        str[top++]=0;

        n=top;
        suffix(10005);
        getheight();
        printf("%d\n",solve(k,nn)-solve(k+1,nn));
    }
    return 0;
}

POJ 3729 Facer’s string (后缀数组)

时间: 2024-10-15 16:49:32

POJ 3729 Facer’s string (后缀数组)的相关文章

POJ3729 Facer’s string 后缀数组

Facer’s string Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 1783   Accepted: 537 Description Minifacer was very happy these days because he has learned the algorithm of KMP recently. Yet his elder brother, Hugefacer, thought that Mini

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

POJ 1743 Musical Theme (后缀数组)

题目大意: 刚才上88个键弹出来的音符. 如果出现重复的,或者是高一个音阶的重复的都算. 思路分析: 具体可以参考训练指南222. height数组表示按照排序后的sa最近的两个后缀的最长前缀. 将height 分块.然后二分答案,二分答案之后去判断是否满足. 要考虑到不重合,还有大于5. 所以二分的时候要从5开始,然后判断的时候要加一个 up - down >len #include <cstdio> #include <iostream> #include <alg

hdu 5030 Rabbit&#39;s String(后缀数组)

题目链接:hdu 5030 Rabbit's String 题目大意:给定k和一个字符串,要求将字符串拆分成k个子串.然后将每个子串中字典序最大的子串选出来,组成一个包含k个字符串的集合,要求这个集合中字典序最大的字符串字典序最小. 解题思路:网赛的时候试图搞了一下这道题,不过水平还是有限啊,后缀数组也是初学,只会切一些水题.赛后看了一下别人的题解,把这题补上了. 首先对整个字符串做后缀数组,除了处理出sa,rank,height数组,还要处理处f数组,f[i]表示说以0~sa[i]开头共有多少

POJ 2406 Power String 后缀数组

这题曾经用KMP做过,用KMP 做非常的简单,h函数自带的找循环节功能. 用后缀数组的话,首先枚举循环节长度k,然后比较LCP(suffix(k + 1), suffix(0)) 是否等于len - k, 如果相等显然k就是一个循环节. 得到LCP的话可以通过预处理出所有点和0的lcp就好了.另外倍增法构造后缀数组还有用RMQ来搞lcp nlogn是不行的,会超时,所以可以dc3走起了.. #include <cstdio> #include <cstring> #include

POJ 题目3581 Sequence(后缀数组)

Sequence Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5738   Accepted: 1227 Case Time Limit: 2000MS Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to cut it into three sub-sequences and

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>

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 1743 Musical Theme(后缀数组+二分答案)

[题目链接] http://poj.org/problem?id=1743 [题目大意] 给出一首曲子的曲谱,上面的音符用不大于88的数字表示, 现在请你确定它主旋律的长度,主旋律指的是出现超过一次, 并且长度不小于5的最长的曲段,主旋律出现的时候并不是完全一样的, 可能经过了升调或者降调,也就是说, 是原来主旋律所包含的数字段同时加上或者减去一个数所得, 当然,两段主旋律之间也是不能有重叠的,现在请你求出这首曲子主旋律的长度, 如果不存在请输出0. [题解] 首先要处理的是升调和降调的问题,由