【后缀数组】【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 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.

∑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

 Solution

题意:给一个串,问你其中正好出现k次的子串有多少个

思路:求出给的串的后缀数组和height数组,然后对于height数组中一个长度k-1的区间,如果两边的值比区间内的最小值(可以RMQ进行O(1)的查询)都要小,那这段区间就是对答案有贡献的。注意k=1时需要特殊处理一下,此时就是后缀数组派上用场的时候了。有不少细节在里面,具体请看代码。还有一个坑到哭泣的地方:由于是多组数据,一定要记得每次清空height数组(不清空的话如果这次的字符串比上一次的短,访问height[n+1]时预期的是0,但实际上是上次字符串的height值),否则要找十年才知道WA在哪。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define MAXN 101111
  4 using namespace std;
  5 char s[MAXN];
  6 int t1[MAXN],t2[MAXN],cc[MAXN],sa[MAXN],rnk[MAXN],height[MAXN];
  7 int len;
  8 bool cmp(int *y,int a,int b,int k)
  9 {
 10     int a1=y[a];
 11     int b1=y[b];
 12     int a2=a+k>=len ? -1:y[a+k];
 13     int b2=b+k>=len ? -1:y[b+k];
 14     return a1==b1 && a2==b2;
 15 }
 16 int make_sa()
 17 {
 18     int *x=t1,*y=t2;
 19     int m=30;
 20     for(int i=0; i<m; i++) cc[i]=0;
 21     for(int i=0; i<len; i++) ++cc[x[i]=s[i]-‘a‘];
 22     for(int i=1; i<m; i++) cc[i]+=cc[i-1];
 23     for(int i=len-1; i>=0; i--) sa[--cc[x[i]]]=i;
 24
 25     for(int k=1; k<=len; k<<=1)
 26     {
 27         int p=0;
 28         for(int i=len-k; i<len; i++) y[p++]=i;
 29         for(int i=0; i<len; i++)
 30            if( sa[i]>=k ) y[p++]=sa[i]-k;
 31
 32         for(int i=0; i<m; i++) cc[i]=0;
 33         for(int i=0; i<len; i++) ++cc[x[y[i]]];
 34         for(int i=1; i<m; i++) cc[i]+=cc[i-1];
 35         for(int i=len-1; i>=0; i--) sa[--cc[x[y[i]]]]=y[i];
 36
 37         swap(x,y);
 38         m=1; x[sa[0]]=0;
 39         for(int i=1; i<len; i++)
 40           x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++;
 41
 42         if( m>=len ) break;
 43     }
 44 }
 45 void make_height()
 46 {
 47     for(int i=0; i<len; i++) rnk[sa[i]]=i;
 48     height[0]=0;
 49     int k=0;
 50     for(int i=0; i<len; i++)
 51     {
 52         if(!rnk[i]) continue;
 53         int j=sa[rnk[i]-1];
 54         if(k) k--;
 55         while(s[i+k]==s[j+k]) k++;
 56         height[rnk[i]]=k;
 57     }
 58 }
 59
 60
 61 int n,minl[100022][18];
 62
 63 void S_table(){
 64     int l = log(len) / log(2);
 65     for(int j = 1;j <= l;++j){
 66         for(int i = 1;i + (1 << (j - 1)) - 1 <= len;++i){
 67             minl[i][j] = min(minl[i][j-1],minl[i+(1<<(j-1))][j-1]);
 68         }
 69     }
 70 }
 71
 72 int rmq(int l,int r){
 73     int k = log(r-l+1) / log(2);
 74     return min(minl[l][k],minl[r-(1<<k)+1][k]);
 75 }
 76
 77
 78 int T,k,cnt[30];
 79
 80 int main(){
 81     cin >> T;
 82     while(T--){
 83         int ans = 0;
 84         memset(height,0,sizeof height);    /**< !!! */
 85         scanf("%d",&k);
 86         scanf("%s",s); len = strlen(s);
 87         make_sa();
 88         make_height();
 89         n = len - 1;
 90         for(int i = 0;i < 100022;++i) minl[i][0] = 1e9;
 91         for(int i = 1;i <= len;++i)
 92             minl[i][0] = height[i];
 93         S_table();
 94
 95
 96         if(k == 1){
 97             for(int i = 1;i <= n+1;++i){
 98                 int tmp = len - sa[i-1];
 99                 if(height[i-1] < tmp && height[i] < tmp)
100                     ans += tmp - max(height[i-1],height[i]);
101             }
102             printf("%d\n",ans);
103             continue;
104         }
105
106         for(int i = 1;i <= n - k + 2;++i){
107             int tmp = rmq(i,i+k-2);
108             if(height[i-1] < tmp && height[i+k-1] < tmp)
109                 ans += tmp - max(height[i-1],height[i+k-1]);
110         }
111
112         printf("%d\n",ans);
113     }
114 }
时间: 2024-10-10 05:03:39

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

HDU 6197 array array array 2017沈阳网络赛 LIS

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6197 题意:给你n个数,问让你从中删掉k个数后(k<=n),是否能使剩下的序列为非递减或者非递增序列 解法:签到题,就是让你求最长不下降子序列长度len,然后判断下n-len是否小于k(将序列反着存下来然后再求即最长不上升子序列,取两者len中的较大值),然后直接套nlogn的模板即可. #include <bits/stdc++.h> using namespace std; const

2017ICPC沈阳网络赛 HDU 6025 -- card card card(最大子段和)

card card card Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1230    Accepted Submission(s): 549 Problem Description As a fan of Doudizhu, WYJ likes collecting playing cards very much. One day

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=1770 题解:一开始理解错题意,以为是abcxxxcba(xxx为v),开心地打了后缀数组后发现哎样例不对丫.. UVA的意思是abcxxxabc(xxx为v). 类似poj3693,我们暴

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 

HDU - 4734 F(x) (2013成都网络赛,数位DP)

题意:求0-B的满足<=F[A]的所有可能 思路:数位DP,记忆化搜索 #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; int A, B; int dp[20][200000]; int bit[20]; int dfs(int cur, int num, int flag) { if (cur == -

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 time

HDU_6194 后缀数组+RMQ

好绝望的..想了五个多小时,最后还是没A...赛后看了下后缀数组瞬间就有了思路...不过因为太菜,想了将近两个小时才吧这个题干掉. 首先,应当认为,后缀数组的定义是,某字符串S的所有后缀按照字典序有小到大的顺序排列(使用下标表示后缀).因为具体过程没太看懂,但是参见刘汝佳蓝书<算法竞赛黑暗圣典>可以得到一个聪明的NLOGN的神器算法.不过这个不太重要. 之后还可以通过他在LCP问题中提到的RANK,height数组相关算法,处理出来height数组,之后其他的可以扔掉. <黑暗圣典>

Codeforces Round #422 (Div. 2) E. Liar 后缀数组+RMQ+DP

E. Liar The first semester ended. You know, after the end of the first semester the holidays begin. On holidays Noora decided to return to Vi?kopolis. As a modest souvenir for Leha, she brought a sausage of length m from Pavlopolis. Everyone knows th