017 ACM/ICPC Asia Regional Shenyang Online 1001 后缀数组+单调队列
2017-09-13 11:57
232 查看
string string string
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2052 Accepted Submission(s): 302
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
1.所有子串,考虑后缀数组解
2.画出后缀数组
aabaaab
aaab
2aab
3aabaaab
1ab
2abaaab
0b
1baaab
3.观察,设某个子串下标为[i],考虑 如果重复K次 那么该序列存在 k-1个子串的最小值为x,即min(height[i],height[i+1]...height[i+k-2]); 设两端点最大值为 y=max(height[i-1],height[i+k-1]),那么对于这K个子串,恰好重复k次的子串为 mex(i,i+y+1),mex(i,i+y+2)...mex(i,i+y+x);
4.维护 x值 ,即为rmq问题,可以采用线段树,st,树状数组等算法,这里可以考虑单调队列,实现简单且O(n)算法。
下面贴出代码
#include <iostream> #include <cstring> #include <queue> #include <cstdio> #define F(x) ((x)/3+((x)%3==1?0:tb)) #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) #define maxn 101000 using namespace std; typedef long long ll; int wa[maxn],wb[maxn],wv[maxn],wss[maxn]; int r[maxn*3],sa[maxn*3],height[maxn],ranks[maxn]; int c0(int *r,int a,int b) { return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2]; } int c12(int k,int *r,int a,int b) { if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1); else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1]; } void sort(int *r,int *a,int *b,int n,int m) { int i; for(i=0;i<n;i++) wv[i]=r[a[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--) b[--wss[wv[i]]]=a[i]; return; } void dc3(int *r,int *sa,int n,int m) { int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p; r =r[n+1]=0; for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i; sort(r+2,wa,wb,tbc,m); sort(r+1,wb,wa,tbc,m); sort(r,wa,wb,tbc,m); for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++) rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++; if(p<tbc) dc3(rn,san,tbc,p); else for(i=0;i<tbc;i++) san[rn[i]]=i; for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3; if(n%3==1) wb[ta++]=n-1; sort(r,wb,wa,ta,m); for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i; for(i=0,j=0,p=0;i<ta && j<tbc;p++) sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++]; for(;i<ta;p++) sa[p]=wa[i++]; for(;j<tbc;p++) sa[p]=wb[j++]; return; } void calheight(int *r,int *sa,int n) { memset(ranks,0,sizeof(ranks)); int i,j,k=0; for(i=1;i<=n;i++) ranks[sa[i]]=i; for(i=0;i<n;height[ranks[i++]]=k) for(k?k--:0,j=sa[ranks[i]-1];r[i+k]==r[j+k];k++); return; } char s[maxn]; struct node{ int x; int index; node(){ } node(int x,int index){ this->x=x; this->index=index; } }; deque <node> q; int ans[maxn]; ll slove(int k,int n){ q.clear(); memset(ans,0,sizeof(ans)); if(k!=1){ for(int i = 2 ; i<=k ; i++){ while(!q.empty()&&height[i]<=q.back().x){ q.pop_back(); } q.push_back(node(height[i],i)); } ans[2]=q.front().x; for(int i = k+1 ; i<=n ; i++){ while(!q.empty()&&height[i]<=q.back().x){ q.pop_back(); } q.push_back(node(height[i],i)); while(q.front().index<=(i-k+1)){ q.pop_front(); } ans[i-k+2]=q.front().x; } ll num=0; for(int i = 2 ; i<=n-k+2 ; i++){ int b=height[i+k-1]; if(i+k-1>n){ b=0; } int c=max(height[i-1],b); if(ans[i]>c){ num+=(ans[i]-c); } } return num; } else{ ll num=0; for(int i = 1 ; i<=n ; i++){ ans[i]=n-sa[i]; } for(int i = 1 ; i<=n ; i++){ int a=height[i]; int b=height[i+1]; if(i==n){ b=0; } if(ans[i]-max(a,b)>0) num+=(ans[i]-max(a,b)); } return num; } } int main() { int t; scanf("%d",&t); while(t--){ int k; scanf("%d",&k); scanf("%s",s); m int len=strlen(s); memset(sa,0,sizeof(sa)); memset(r,0,sizeof(r)); for(int i = 0 ; s[i] ; i++){ r[i]=s[i]; } dc3(r,sa,len+1,256); calheight(r,sa,len); printf("%lld\n",slove(k,len)); } return 0; }
相关文章推荐
- 2017 ACM/ICPC Asia Regional Shenyang Online 1001(hdu 6194)
- HDU-2017 ACM/ICPC Asia Regional Shenyang Online-1001-string string string
- 2016 ACM/ICPC Asia Regional Shenyang Online HDU 5893 List wants to travel
- 【HDU5895 2016 ACM ICPC Asia Regional Shenyang Online D】【公式转化 矩阵快速幂 欧拉定义】Mathematician QSC 递推数列前n平方项和
- 2017 ACM/ICPC Asia Regional Shenyang Online 1005 & hdu6198:number number number
- 2017 ACM/ICPC Asia Regional Shenyang Online array
- HDU 5898 odd-even number(2016 ACM/ICPC Asia Regional Shenyang Online)
- 2017 ACM/ICPC Asia Regional Qingdao Online 1001/HDUOJ 6206 Apple
- 2017 ACM/ICPC Asia Regional Shenyang Online card card card
- hdu 5451(2015 ACM/ICPC Asia Regional Shenyang Online)
- hdu 5878 I Count Two Three (2016 ACM/ICPC Asia Regional Qingdao Online 1001)
- HDU 5895 Mathematician QSC(矩阵乘法+循环节降幂+除法取模小技巧+快速幂)——2016 ACM/ICPC Asia Regional Shenyang Online
- HDU 5895 Mathematician QSC(矩阵乘法+循环节降幂+除法取模小技巧+快速幂)——2016 ACM/ICPC Asia Regional Shenyang Online
- 【HDU5896 2016 ACM ICPC Asia Regional Shenyang Online E】【DP 排列组合 分治ntt】Running King n个点构成含环无向图的方案数.cp
- 2017 ACM/ICPC Asia Regional Shenyang Online 1002 & hdu6195:cable cable cable
- HDU 6201 transaction transaction transaction (Dijstra, 2017 ACM/ICPC Asia Regional Shenyang Online)
- [Contests]2016 ACM/ICPC Asia Regional Qingdao Online(1001/2/4/5/6)
- 2017 ACM/ICPC Asia Regional Qingdao Online 1001-Apple(Java大实数类BigDecimal应用)(已知三点坐标求圆心坐标和半径)
- HDU 5437.Alisha’s Party【2015 ACM/ICPC Asia Regional Changchun Online】【优先队列】9月14
- HDU 5461.Largest Point【2015 ACM/ICPC Asia Regional Shenyang Online】【排序】9月19