• [NOI2016]优秀的拆分


    [NOI2016]优秀的拆分

    题目大意:

    如果一个字符串可以被拆分为(AABB)的形式,其中(A)(B)是任意非空字符串,则这种拆分方式是优秀的。给出一个长度为(n(nle30000))的字符串(S),求其子串所有拆分方式中优秀拆分的总个数。

    思路:

    若用(f[i])表示以(i)结尾的可以表示为(AA)形式的后缀数,用(g[i])表示以(i)开头的可以表示为(AA)形式的前缀数。则答案为(sum_{i=1}^{n-1}f[i] imes g[i+1])。这样我们就把原问题转化为只需要考虑前/后缀为(AA)形式的问题。

    枚举(A)的长度(l),每隔(l)设置一个关键点(p)。对于一对相邻的关键点(p_i)(p_{i+1}),我们求(l_1=min(operatorname{lcs}(p_i,p_{i+1}),l))(l_2=min(operatorname{lcp}(p_i,p_i+1),l))。若(l_1+l_2-1ge l),则存在这样的(AA),我们可以算出所有合法位置,(f)(g)区间(+1),可以使用差分维护。

    (operatorname{lcs})(operatorname{lcp})可以用哈希+二分实现,枚举(l)的时间复杂度是调和级数(mathcal O(nlog n))。总时间复杂度(mathcal O(nlog^2n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    typedef long long int64;
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=30001;
    const int base=31,mod=998244353;
    char s[N+1];
    int n,hash[N],pwr[N],f[N],g[N];
    inline int idx(const char &ch) {
    	return ch-'a'+1;
    }
    inline int calc(const int &l,const int &r) {
    	return (hash[r]-(int64)hash[l-1]*pwr[r-l+1]%mod+mod)%mod;
    }
    inline int lcs(const int &p1,const int &p2,const int &lim) {
    	int l=1,r=std::min(p1,lim);
    	while(l<=r) {
    		const int mid=(l+r)>>1;
    		if(calc(p1-mid+1,p1)==calc(p2-mid+1,p2)) {
    			l=mid+1;
    		} else {
    			r=mid-1;
    		}
    	}
    	return l-1;
    }
    inline int lcp(const int &p1,const int &p2,const int &lim) {
    	int l=1,r=std::min(n-p2+1,lim);
    	while(l<=r) {
    		const int mid=(l+r)>>1;
    		if(calc(p1,p1+mid-1)==calc(p2,p2+mid-1)) {
    			l=mid+1;
    		} else {
    			r=mid-1;
    		}
    	}
    	return l-1;
    }
    int main() {
    	for(register int i=pwr[0]=1;i<N;i++) {
    		pwr[i]=(int64)pwr[i-1]*base%mod;
    	}
    	for(register int T=getint();T;T--) {
    		scanf("%s",&s[1]);
    		n=strlen(&s[1]);
    		for(register int i=hash[0]=1;i<=n;i++) {
    			f[i]=g[i]=0;
    			hash[i]=((int64)hash[i-1]*base+idx(s[i]))%mod;
    		}
    		for(register int l=1;l<=n/2;l++) {
    			for(register int p1=l;p1<=n-l;p1+=l) {
    				const int p2=p1+l;
    				const int l1=lcs(p1,p2,l),l2=lcp(p1,p2,l);
    				if(l1+l2-1>=l) {
    					f[p2-l1+l]++;
    					f[p2+l2]--;
    					g[p1-l1+1]++;
    					g[p1+l2-l+1]--;
    				}
    			}
    		}
    		for(register int i=1;i<=n;i++) {
    			f[i]+=f[i-1];
    			g[i]+=g[i-1];
    		}
    		int64 ans=0;
    		for(register int i=1;i<n;i++) {
    			ans+=(int64)f[i]*g[i+1];
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    tensorflow2中pydot问题
    tensorflow2的差异总结
    tensorflow2.0中引入keras和原来的keras的差异
    Linux 后台任务进程管理工具supervisor的使用
    【Go学习】go 原生库net/http发送 GET POST 请求
    正则校验crontab格式
    【FastAPI 学习十二】定时任务篇
    【FastAPI 学习 十一】 项目目录结构demo(自己改版)
    【FastAPI 学习 十】使用Redis
    【FastAPI 学习 九】图片文件上传
  • 原文地址:https://www.cnblogs.com/skylee03/p/9174983.html
Copyright © 2020-2023  润新知