hdu 6194 沈阳网络赛--string string string(后缀数组)

题目链接

Problem Description

Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k times as an important string, and you need to find out how many substrings which are important strings.

Input

The first line contains an integer T (T≤100) implying the number of test cases.
For each test case, there are two lines:
the first line contains an integer k (k≥1) which is described above;
the second line contain a string s (length(s)≤105).
It‘s guaranteed that ∑length(s)≤2∗106.

Output

For each test case, print the number of the important substrings in a line.

Sample Input

2

2

abcabc

3

abcabcabcabc

Sample Output

6

9

题意:有一个字符串s,求其中恰好出现k次的子串有多少个?

思路:后缀数组,通过后缀数组算法可以知道每个后缀的排名,如果有某个子串恰好出现k次,那么必定有k个对应的后缀 即这个子串是这k个后缀串的前缀,那么这k个后缀串的排名一定是连续的,所以我们按排名从1~len(s)依次开始 取连续k个后缀串,可以根据height[]数组快速算出当前这k个后缀串的最大公共前缀长度len,那么长为1到len的前缀子串,这k个串都含有,设当前开始k个串为 i到i+k-1 ,那么如果子串长过短,可能 i-1 或 i+k 这个串也含有相应的子串,所以计算出 i 和 i-1 串,i+k和i+k-1的最大公共前缀长为m,那么之前取的子串长必须大于m才能保证 i-1 和 i+k 不含有相应的子串,只有i~i+k-1这k个串含有相应的子串。

代码如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=1e5+5;
char s[N];
int k;
int wa[N],wb[N],wv[N],wss[N];
int sa[N],ran[N],height[N];
int f[N][20];

int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(char *r,int *sa,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0; i<m; i++) wss[i]=0;
    for(i=0; i<n; i++) wss[x[i]=(int)r[i]]++;
    for(i=1; i<m; i++) wss[i]+=wss[i-1];
    for(i=n-1; i>=0; i--) sa[--wss[x[i]]]=i;
    for(j=1,p=1; p<n; j*=2,m=p)
    {
        for(p=0,i=n-j; i<n; i++) y[p++]=i;
        for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;

        for(i=0; i<n; i++) wv[i]=x[y[i]];
        for(i=0; i<m; i++) wss[i]=0;
        for(i=0; i<n; i++) wss[wv[i]]++;
        for(i=1; i<m; i++) wss[i]+=wss[i-1];
        for(i=n-1; i>=0; i--) sa[--wss[wv[i]]]=y[i];

        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    return;
}
void callheight(char *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++)
        ran[sa[i]]=i;
    for(i=0;i<n;height[ran[i++]]=k)
    for(k?k--:0,j=sa[ran[i]-1];r[i+k]==r[j+k];k++);
    return ;
}
void init(int len)
{
    for(int i=1;i<=len;i++) f[i][0]=height[i];
    for(int s=1;(1<<s)<=len;s++)
    {
        int tmp=(1<<s);
        for(int i=1;i+tmp-1<=len;i++)
        {
            f[i][s]=min(f[i][s-1],f[i+tmp/2][s-1]);
        }
    }
}
int cal(int l,int r)
{
    int len=log2(r-l+1);
    int ans=min(f[l][len],f[r-(1<<len)+1][len]);
    return ans;
}
int main()
{
    int T; cin>>T;
    while(T--)
    {
       scanf("%d%s",&k,s);
       int len=strlen(s);
       da(s,sa,len+1,130);
       callheight(s,sa,len);
       init(len);
       int ans=0;
       for(int i=1;i+k-1<=len;i++)
       {
           int j=i+k-1;
           int tmp=height[i];
           if(j+1<=len) tmp=max(tmp,height[j+1]);
           int x;
           if(k!=1) { x=cal(i+1,j); }
           else x=len-sa[i];
           ans+=max(0,x-tmp);
       }
       printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-10 17:06:37

hdu 6194 沈阳网络赛--string string string(后缀数组)的相关文章

HDU 5008西安网络赛B题:后缀数组求第k小子串

思路:尼玛,这题搞了一天了,比赛的时候用了n^2的方法绝对T了,然后今天看别人代码看了一天才知道.后面感觉也挺容易的,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛的时候这个技巧竟然抛在脑后了,然后就不会了. 但是今天自己用了自己的两个后缀数组的模板(倍增和DC3)的都WA了,搞得自己真想跳楼去了!! 到现在都不知道到底是哪里错了,处理的方法和标准做法都一样,但是就是WA,然后用了别人的模板,再用自己的处理方法就过了,怀疑自己的两个模板是不是哪里错

2015沈阳网络赛1003 Minimum Cut 树链剖分 数组维护前缀和进行区间增减

2015沈阳网络赛1003  Minimum Cut   树链剖分 数组维护前缀和进行区间增减 Minimum Cut Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Given a simple unweighted graph G 

2019ACM-ICPC沈阳网络赛-C-Dawn-K&#39;s water(完全背包模板题)

Dawn-K's water  1000ms 262144K Dawn-K recently discovered a very magical phenomenon in the supermarket of Northeastern University: The large package is not necessarily more expensive than the small package. On this day, Dawn-K came to the supermarket

2019ACM-ICPC沈阳网络赛-K-Guanguan&#39;s Happy water(思维+暴力)

Guanguan's Happy water 4000ms 262144K Rather than drinking happy water, Guanguan loves storing happy water. So he bought a refrigerator and stored a_iai? bottles of cola into it every day. When the storage is finished on the kk-th day, the refrigerat

【后缀数组】【RMQ】HDU 6194 - string string string (2017ICPC沈阳网络赛)

string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given a string s and q queries. For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is

HDU5853 Jong Hyok and String(二分 + 后缀数组)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5853 Description Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We

2015长春、沈阳网络赛总结

我所说的总结并不是谈什么题目解法之类的东西 这些东西网上有很多题解 说说这两场网赛吧! 这两场我的状态还行,只是xiaodong还没有找到状态,长春赛lucas+中国剩余定理他硬是打了一整场,还是没打出来,版题没打出来确实不该 wzb状态一般,不过看题的能力依然那么厉害 长春赛中,很遗憾的只出了5道题,按当时过题数目,应该是7道德,可是小东的lucas那题没打出来,而我打得后缀数组那题,当顺时针的时候不用看是否是下标最前面的,但是反过来就需要看了,当时想当然的认为不用,交了4发,一直wa到比赛结

HDU 6205 2017沈阳网络赛 思维题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6205 题意:给你n堆牌,原本每一堆的所有牌(a[i]张)默认向下,每次从第一堆开始,将固定个数的牌(b[i]张)翻上,然后下一堆继续,直到没有足够的牌翻上,然后你可以获得当前已经操作过的堆的所有牌.最初你可以调整堆的顺序,把第一堆放到最后一堆(逆时针旋转),你可以重复这个操作,问你要重复多少次这个操作,才能获得最多的牌. 解法:先把这个序列复制一遍放在原来的序列后面.当i=n的时候结束就可以了,每次