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


    2021HDU多校第四场 HDU6975 Display Substring

    题意

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

    (1le nle 10^5,1le kle frac{n(n+1)}{2},sum|S|le8 imes10^5,1le c_alphale 100)

    题解

    二分答案,考虑如何统计(S)中是否有(k)个比权值当前答案小的不同字串。首先对(S)(SAM),由于字符的权值都是正的,显然串越长,其权值越大,又由于(parent)树上的每个节点代表(S)中某个前缀的一段连续后缀,我们可以直接对(parent)树上的每个节点分别二分将结果加起来即可。复杂度(O(nlog^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
    ");g.init2();return ;}
    	printf("%lld
    ",ans);
    	g.init2();
    }
    int main(){
    	int t;scanf("%d",&t);
    	while(t--)
    		f1();
    	return 0;
    }
    
  • 相关阅读:
    网络操作系统(WebOS)网站
    各种邀请码:Evernote 3.0,wallop,qolin等等
    urlrewrite 的使用方法
    一次事故处理情况(mysql 相关)
    开始使用ubuntu办公
    Q邻:网络桌面
    数据库表字段命名规范
    计算机专业导学
    详解GCC的下载和安装
    三层的解释
  • 原文地址:https://www.cnblogs.com/bobh/p/15092782.html
Copyright © 2020-2023  润新知