zoukankan      html  css  js  c++  java
  • CF1393E2

    CF1393E2 - Twilight and Ancient Scroll (harder version)

    题目大意

    给定(n)个串(S_i),求在每个串中至多删除一个字符(可以删到空)

    最终(S'_i)字典序单调不减的方案数



    dp

    显然是记录上一个串删除的位置(j),得到(dp_j),依次考虑每个串

    (S)为当前串,(T)为上一个串

    每次我们枚举当前串删除的位置(i),不妨设得到的新串为(S'),考虑对于(S')找到所有合法转移

    (L=LCP(S,T)),在(T)中删除位置为(t)

    1.(t>L+1)

    则可以根据(T_{L+1})(S'_{L+1})的关系确定(T')(S')的关系,只需要处理一个后缀和(suf_i)


    2.设(p)(T_{L+1})向前延伸且字符相同的最长位置,(tin[p,L+1])

    此时,删除(T_t)可能会使得(L'>L),所以提出来特殊处理

    显然(tin[p,L+1]Leftrightarrow t=L+1),那么对于得到的新串可以再求(LCP(S',T'))来判断大小

    只需要一个区间和


    3.(t<p),此时(L'=LCP(S',T')<L)

    由于(L'<L),比较(S',T')相当于比较(T_{t:},T_{t+1:})

    其中(T_{t:})表示(T)(t)开始的后缀,那么预处理找到所有合法的(t),累前缀和即可得到(pre_{p-1})


    关于实现

    ( ext{SA,SAM})就完蛋了

    由于删除一个字符之后,求(LCP)的两个串就是在原串基础上进行(pm 1)的偏移

    线性预处理三个(LCP)数组即可,当然真正求的时候需要分类讨论一下(真的,就一下/md)


    判断(T_{t:},T_{t+1:})容易倒着线性预处理出来,在代码里是(chk_i)


    所有操作均可以线性处理,时间复杂度为(O(L)),77ms

    Tips:

    比较过程中容易出现奇妙的越界,我写得很丑

    const int N=1e6+10,P=1e9+7;
    
    int n,m;
    char A[2][N],*S=A[0],*T=A[1];
    int X[N],Y[N],Z[N];
    int dp[N],F[N],suf[N],pre[N],chk[N],L[N];
    
    int main(){
    	rep(_,1,rd()) {
    		swap(S,T),swap(n,m);
    		scanf("%s",S+1),n=strlen(S+1);
    		rep(i,n+1,m+2) S[i]=1;
    		rep(i,m+1,n+2) T[i]=-1;
    		if(!m) {
    			rep(i,1,n+1) dp[i]=1;
    			continue;
    		}
    		rep(i,max(n,m)+1,i+2) X[i]=Y[i]=Z[i]=0;
    		drep(i,max(n,m),1) {
    			X[i]=S[i]==T[i]?X[i+1]+1:0;
    			Y[i]=S[i]==T[i+1]?Y[i+1]+1:0;
    			Z[i]=S[i+1]==T[i]?Z[i+1]+1:0;
    		}
    
    		// initiate
    		suf[m+2]=0;
    		drep(i,m+1,1) suf[i]=suf[i+1]+dp[i],Mod1(suf[i]);
    		drep(i,m,1) chk[i]=T[i]!=T[i+1]?T[i]>T[i+1]:chk[i+1];
    		rep(i,1,m+1) L[i]=T[i]==T[i-1]?L[i-1]:i;
    		rep(i,1,m) pre[i]=pre[i-1]+chk[i]*dp[i],Mod1(pre[i]);
    
    
    		rep(i,1,n+1) {
    			int l=min(X[1],i-1);
    			if(l==i-1) l+=Z[i];
    			F[i]=0;
    
    			auto I=[&](int x){ return (x>=i)+x; };
    
    			// type1 , deleted pos > l+1
    			if(T[l+1]<=S[I(l+1)]) F[i]+=suf[l+2],Mod1(F[i]);
    			int p=L[l+1];
    			
    			// type2 ,delete T between [p..l+1]  ,the same as we delete T[l+1]
    			int r=0; // r= LCP(S'[l+2],T[l+2]) ,check if delete T[l+1], T'<=S'
    			if(l+1<i) r+=min(i-l-1,Y[l+1]);
    			if(r==max(0,i-l-1)) r+=X[l+2+r];
    			if(T[l+2+r]<=S[I(l+1+r)]) F[i]=(F[i]+0ll+suf[p]-suf[l+2]+P)%P;
    			
    			// type3 , delete T at [1,p-1], so LCP'<l , and we determine T'<=S' by chk[i]
    			F[i]=(F[i]+pre[p-1])%P;
    		}
    		rep(i,1,n+1) dp[i]=F[i];
    	}
    	int ans=0;
    	rep(i,1,n+1) ans+=dp[i],Mod1(ans);
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    【IDEA】创建Maven工程
    【Java】Input,Output,Stream I/O流 03 系统标准流 & 打印流
    【Java】Reflection 反射机制 03调用
    【Java】JDBC Part2 工具类封装实现
    【郝斌C ST】 指针入门
    【Java】Input,Output,Stream I/O流 02 文件流 & 缓冲流
    margin和padding的区别
    JAVA反射机制
    HTTP错误代码详细介绍
    关于Java继承问题
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14738620.html
Copyright © 2011-2022 走看看