2017 ACM/ICPC Asia Regional Shenyang Online 1001(hdu 6194)
来源:互联网 发布:淘宝怎么提升排名靠前 编辑:程序博客网 时间:2024/06/05 21:01
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6194
题意:给你一个k,和一个字符串,让你求出这个字符串有多少子串恰好出现k次 (允许有部分重叠)
思路:后缀数组。 求出height,height[i]表示排名i与排名i-1后缀串的lcp(最长公共前缀)。
则当k>1时,用一个单调队列维护所有区间 [l,r] 长度为 k-1 的height数组的最小值min (根据height的定义,k-1个height数组表示的实则为k个串 ),
若min>height[l-1]&&min>height[r+1]) , 则该区间对答案的贡献为 min-max(height[l-1],height[r+1]).
当k==1时,用所有子串个数减去重复的子串即为答案。 即减掉所有 max(height[i], height[i+1]).
m = max(height[i], height[i+1]) 可以理解为以sa[i]为初始位置的子串的最长重叠数(也即m个有重叠的串),则将这些串都减掉,就是非重叠的串的个数。
代码:
#include <stdio.h>#include <iostream>#include <algorithm>#include <math.h>#include <stdlib.h>#include <string.h>#include <sstream>#include <string>#include <map>#include <vector>#include <stack>#include <time.h>#include <set>#include <queue>#define scan(a) scanf("%d",&a)#define scann(n,m) scanf("%d%d",&n,&m)#define scannn(n,m,w) scanf("%d%d%d",&n,&m,&w)#define print(a) printf("%d\n",a)#define dg(x) cout<<#x<<"="<<x<<endl#define mem(a,n) memset(a,n,sizeof(a))using namespace std;const int inf=0x3f3f3f3f;const int mod=1e9+7;const double eps=1e-8;typedef pair<int,int> PP;typedef long long ll;typedef unsigned long long ull;ll powmod(ll a,ll x,ll mod){ll t=1ll;while(x){if(x&1)t=t*a%mod;a=a*a%mod;x>>=1;}return t;}ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}//==============================================================================================//后缀数组---倍增算法//sa[i] 排在第i位的后缀的首字母的下标(*****由于str最后要补0,故sa[0]=len)//Rank[i] 首字母下标为i的后缀的排名 (Rank[len]=0)//height[i] 排名i与排名i-1后缀的lcp(最长公共前缀)//与后缀串(i)的lcp越大的串,该串排名与lcp越接近(同一方向)const int N=2e5+10;int cmp(int *r,int a,int b,int l){ //用串的两个关键字判断串(a)与串(b)是否相同 return (r[a]==r[b]) && (r[a+l]==r[b+l]);}int wa[N],wb[N],wss[N],wv[N];int Rank[N],height[N];void DA(char *r,int *sa,int n,int m){ //这里的n表示字符串长+1,m为字符取值范围 int i,j,p,*x=wa,*y=wb,*t; //字符串全是字母则m取128,全数字则取max+1 for(i=0;i<m;i++) wss[i]=0; for(i=0;i<n;i++) wss[x[i]=r[i]]++; //统计各个字母的个数 for(i=1;i<m;i++) wss[i]+=wss[i-1]; //wss[i]即为i(对应的字母)的排序 for(i=n-1;i>=0;i--) sa[--wss[x[i]]]=i; //以上是求长度为1时的基数排序) for(j=1,p=1;p<n;j*=2,m=p) //通过已经求出的长度j的SA,来求2*j的SA { for(p=0,i=n-j;i<n;i++) y[p++]=i; // 将没有第二关键字(0)的排在前面 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; // y[] 是第二关键字的 sa[]数组 (功能一致) //以上是按第二关键字排序 for(i=0;i<n;i++) wv[i]=x[y[i]]; //与排在i位的第二关键词匹配的第一关键词的排名 for(i=0;i<m;i++) wss[i]=0; //x为第一关键字的Rank数组(相同串的x值相等) 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]; //***求排在第i位的第二关键词所在匹配的sa值 //以上是两个关键字合并后的基数排序 t=x,x=y,y=t,p=1,x[sa[0]]=0; //先将x东西放y里,而x将保存合并后的Rank数组 for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; //若串(sa(i-1))与串(sa(i))相同,则两串Rank值相等 //故当p=n时,说明所有串Rank值均不相同,即排序完成。退出循环 }}void calheight(char *r,int *sa,int n){ // 求height数组. 此处n为实际长度. int i,j,k=0; // height[]的合法范围为 1-N,其中0是结尾加入的字符 for(i=1;i<=n;i++) Rank[sa[i]]=i; // 根据SA求Rank for(i=0;i<n; height[Rank[i++]] = k ) // 定义:h[i] = height[ Rank[i] ] for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++); //根据 h[i] >= h[i-1]-1 来优化计算height过程}char str[N];int sa[N],k; //sa[i]表示排在第i位的后缀的首字母下标;struct node{ int x,y; node(){} node(int x,int y):x(x),y(y){}}moque[N];int main(){ int T; cin>>T; while(T--){ scan(k); mem(height,0); scanf("%s",str); mem(moque,0); int n = strlen(str); str[n]=0; //*****最后要补0 DA(str,sa,n+1,128); //注意区分此处为n+1,因为添加了一个结尾字符用于区别比较 calheight(str,sa,n); //str可为int数组 ll ans=0; if(k==1){ ans=n*(n+1)/2; // 子串总数 for(int i=1;i<=n;i++) //减掉重复的 ans-= max(height[i],height[i+1]); cout<<ans<<endl; continue; } else if(k>n) {printf("0\n");continue;} int head=0,rear=-1; for(int i=1;i<=n;i++){ //单调队列 while(head<=rear&&moque[rear].x>=height[i]) rear--; //若求区间最大值则将 >= 改为 <= moque[++rear]=node(height[i],i); while( (moque[rear].y-moque[head].y)>=k-1 ) head++; if(i>=k){ int mi=moque[head].x; //队首每个区间最小值 int r=moque[rear].y; if(mi>height[r+1]&&mi>height[r+1-k]) ans+=mi-max(height[r+1],height[r+1-k]); //答案贡献值 } } cout<<ans<<endl; }}
阅读全文
1 0
- 2017 ACM/ICPC Asia Regional Shenyang Online 1001(hdu 6194)
- HDU-2017 ACM/ICPC Asia Regional Shenyang Online-签到题
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional shenyang Online
- HDU-2017 ACM/ICPC Asia Regional Shenyang Online-1001-string string string
- hdu 5451(2015 ACM/ICPC Asia Regional Shenyang Online)
- HDU 5458 Stability (2015 ACM/ICPC Asia Regional Shenyang Online)
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- Python量化交易talib中SMA模块介绍
- hdu 4850 Wow! Such String! 构造 欧拉回路
- Android系统权限说明
- leetcode改进 Reverse Pairs
- struts2框架搭建开发环境
- 2017 ACM/ICPC Asia Regional Shenyang Online 1001(hdu 6194)
- PAT练习(4)-1044 Table Tennis (30)
- [LeetCode]169.Majority Element
- Unity3D 设计模式---策略模式
- 轮播图Banner使用
- HDU 5534 Partial Tree 【完全背包+思维】
- 基于Scikit-Learn的五个文本分类案例研究
- 51NOD 1158 全是1的最大子矩阵
- [初学笔记] matlab中怎么把数据循环写入Excel