• 【ZJ选讲·BZOJ 5073】


    小A的咒语

    给出两个字符串A,B (len<=105)

    现在可以把A串拆为任意段,然后取出不超过 x 段,按在A串中的前后顺序拼接起来

    问是否可以拼出B串。

    【题解】

          ①如果遇上dp空间会炸,可以将那一维状态存入f[]中

          ②f[i][j]表示A串1~i位已经取出了x段,能够匹配B的最远位置的B的下标。

          ③没有后效性,因此DP是合理的:令l=lcp(A[i+1],B[dp[i][j]+1(后缀数组RMQ维护)
                 dp[i+1][j]=max(dp[i+1][j],dp[i][j])  【不包含i】                   

                 dp[i+l][j+1]=max(dp[i+l][j+1],dp[i][j]+l) 【包含i】

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 100005
    using namespace std;
    char s[MAXN*2];
    int sa[MAXN*2],rk[MAXN*2],ht[MAXN*2];
    int dp[MAXN][105],st[MAXN*2][20],log2[MAXN*2];
    void print(int n){
    	puts("sa:");
    	for(int i=0;i<n;i++) printf("%d ",sa[i]); puts("");
    	puts("rk:");
    	for(int i=0;i<n;i++) printf("%d ",rk[i]); puts("");
    	puts("ht:");
    	for(int i=0;i<n;i++) printf("%d ",ht[i]); puts("");
    }
    bool cmp(int *y,int len,int k,int p1,int p2){
    	int a=y[p1],b=y[p2];
    	int aa=p1+k<len?y[p1+k]:-1,bb=p2+k<len?y[p2+k]:-1;
    	return a==b&&aa==bb;
    }
    void build(int n,int m){
    	static int wa[MAXN*2],wb[MAXN*2],c[MAXN*2],*x,*y,p;
    	x=wa; y=wb;
    	for(int i=0;i<m;i++) c[i]=0;
    	for(int i=0;i<n;i++) c[x[i]=s[i]]++;
    	for(int i=1;i<m;i++) c[i]+=c[i-1];
    	for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    	for(int k=1;k<n;k<<=1){
    		p=0;
    		for(int i=n-k;i<n;i++) y[p++]=i;
    		for(int i=0;i<n;i++) if(sa[i]-k>=0) y[p++]=sa[i]-k;
    		
    		for(int i=0;i<m;i++) c[i]=0;
    		for(int i=0;i<n;i++) c[x[y[i]]]++;
    		for(int i=1;i<m;i++) c[i]+=c[i-1];
    		for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
    		
    		m=1; swap(x,y); x[sa[0]]=0;
    		for(int i=1;i<n;i++)
    			x[sa[i]]=cmp(y,n,k,sa[i-1],sa[i])?m-1:m++;
    		if(m>=n) break;
    	}
    	for(int i=0;i<n;i++) rk[sa[i]]=i;
    	int h=0;
    	for(int i=0,j;i<n;i++){
    		if(h) h--;
    		if(rk[i]!=0){
    			j=sa[rk[i]-1];
    			while(i+h<n&&j+h<n&&s[i+h]==s[j+h]) h++;
    		}
    		ht[rk[i]]=h;
    	}
    	for(int i=1;i<n;i++) st[i][0]=ht[i];
    	for(int k=1;(1<<k)<n;k++)
    		for(int i=1<<k;i<n;i++)
    			st[i][k]=min(st[i-(1<<(k-1))][k-1],st[i][k-1]);
    }
    int lcp(int i,int j){
    	i=rk[i]; j=rk[j];
    	if(i>j) swap(i,j); i++;
    	int k=log2[j-i+1];
    	return min(st[i+(1<<k)-1][k],st[j][k]);
    }
    int main(){
    	log2[1]=0;
    	for(int i=2;i<200000;i++) log2[i]=log2[i>>1]+1;
    	int T; scanf("%d",&T); 
    	while(T--){
    		int n,m,x; bool fg;
    		memset(dp,0,sizeof(dp));
    		scanf("%d%d%d",&n,&m,&x);
    		scanf("%s",s); s[n]='%';
    		scanf("%s",s+n+1); fg=0;
    		build(n+m+1,301);
    		for(int i=-1;i<n;i++)
    			for(int j=0;j<=min(i+1,x);j++){
    				int d=i>=0?dp[i][j]:0;
    				if(d==m) fg=1;
    				dp[i+1][j]=max(dp[i+1][j],d);
    				int l=(i+1<n&&n+1+d<n+m+1)?lcp(i+1,n+1+d):0;
    				if(l==0) continue;
    				dp[i+l][j+1]=max(dp[i+l][j+1],d+l);
    			}
    		if(fg) printf("YES
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }//*ZJ

    .

  • 相关阅读:
    Golang的标准命令简述
    Golang的环境安装
    初识Golang编程语言
    基于Ambari的WebUI部署Hive服务
    基于Ambari Server部署HDP集群实战案例
    HBase shell常用命令总结
    HBase完全分布式集群搭建
    HBase工作原理概述
    面向对象-接口(interface)实战案例
    myBatis 简介
  • 原文地址:https://www.cnblogs.com/Damitu/p/7770930.html
Copyright © 2020-2023  润新知