ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】2021HDU多校第四场 HDU6975 Display Substring

2021-08-03 09:35:21  阅读:162  来源: 互联网

标签:le 第四场 int 题解 ll 2021HDU mid 权值 void


2021HDU多校第四场 HDU6975 Display Substring

题意

给出26个小写字母的权值\(c_\alpha\),定义一个串\(S\)的权值为其所有字符的权值和。现给出一个仅由小写字符组成的串\(S\),求其所有本质不同的子串中权值第\(k\)小的串。

\(1\le n\le 10^5,1\le k\le \frac{n(n+1)}{2},\sum|S|\le8\times10^5,1\le c_\alpha\le 100\)

题解

二分答案,考虑如何统计\(S\)中是否有\(k\)个比权值当前答案小的不同字串。首先用对\(S\)建\(SAM\),由于字符的权值都是正的,显然串越长,其权值越大,又由于\(parent\)树上的每个节点代表\(S\)中某个前缀的一段连续后缀,我们可以直接对\(parent\)树上的每个节点分别二分将结果加起来即可。复杂度\(O(n\log^2n)\)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define I inline 
using namespace std;
typedef long long ll;
const int N=800005,M=26;
char S[N];
int n,m,x,y,c[M];
ll ss[N],K;
ll getlr(int x,int y){return ss[y]-ss[x-1];}
struct sam{
	int fa[N],sz[N],len[N],lst,gt,ch[N][M],pos[N];
	void init(){gt=lst=1;}
	void init2(){
		for(int p=1;p<=gt;p++){
			pos[p]=0;
			memset(ch[p],0,sizeof(ch[p]));
		}
		lst=gt=1;
	}
	void ins(int c,int id){
		int f=lst,p=++gt;lst=p;
		len[p]=len[f]+1;sz[p]=1;pos[p]=id;
		while(f&&!ch[f][c])ch[f][c]=p,f=fa[f];
		if(!f){fa[p]=1;return ;}
		int x=ch[f][c],y=++gt;
		if(len[x]==len[f]+1){gt--;fa[p]=x;return ;}
		len[y]=len[f]+1;pos[y]=pos[x];fa[y]=fa[x];fa[x]=fa[p]=y;
		for(int i=0;i<M;i++)ch[y][i]=ch[x][i];
		while(f&&ch[f][c]==x)ch[f][c]=y,f=fa[f];
	}
	int A[N],c[N];
	void rsort(){
		for(int i=1;i<=gt;i++){c[i]=0;}
		for(int i=1;i<=gt;i++)++c[len[i]];
		for(int i=1;i<=gt;i++)c[i]+=c[i-1];
		for(int i=gt;i>=1;i--){A[c[len[i]]--]=i;}
	}
	void f1(){
		rsort();
	}
	int ck(ll k){
		ll res=0;
		for(int i=2;i<=gt;i++){
			int l=1,r=len[i]-len[fa[i]],mid=0;
			int ans=0;
			while(l<=r){
				mid=l+r>>1;
				if(getlr(pos[i]-mid+1-len[fa[i]],pos[i])<=k){
					ans=mid;
					l=mid+1;
				}
				else{r=mid-1;}
			}
			res+=ans;
		}
		return res>=K;
	}
}g;

void f1(){
	scanf("%d%lld%s",&n,&K,S+1);
	g.init();
	for(int i=1;i<=n;i++){
		g.ins(S[i]-'a',i);
		//upd(rt[g.lst],1,n,i);
	}
	for(int i=0;i<M;i++){scanf("%d",&c[i]);}
	for(int i=1;i<=n;i++){ss[i]=ss[i-1]+c[S[i]-'a'];}
	ll ans=0,l=0,r=ss[n],mid=0;
	while(l<=r){
		mid=l+r>>1;
		if(g.ck(mid)){ans=mid;r=mid-1;}
		else{l=mid+1;}
	}
	if(ans<=0||ans>ss[n]){printf("-1\n");g.init2();return ;}
	printf("%lld\n",ans);
	g.init2();
}
int main(){
	int t;scanf("%d",&t);
	while(t--)
		f1();
	return 0;
}

标签:le,第四场,int,题解,ll,2021HDU,mid,权值,void
来源: https://www.cnblogs.com/bobh/p/15092782.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有