• LibreOJ #10047


    应同机房某大佬的要求来写这篇题解

    Description

    给定一个字符串 (S) 和一个数 (K),要求求出 (S) 的所有形似 (A+B+A) 的子串数量,其中 (mid Amid ge K)(mid Bmid ge 1)

    位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串

    Solution

    (S) 的长度为 (n)

    对于 (S)(1)(n) 的每一个位置,以当前位置的字符作为一个子串的起点,然后寻找它的终点,来确定当前子串是否满足条件

    对于 (Next) 数组的预处理还是相同操作,但是每换一个起点就要重新处理一次,只处理从当前位置到最后的字符

    对于每个子串的终点,可以发现,只要在满足总长度的情况下不停回溯,才能统计所有的情况

    回溯到最后的位置就是与它相同的最初子串的结束位置,因为不同位置相同子串算作同一子串,所以遇到相同的时,回溯到第一个相同子串便可统计

    同理,若第一个相同子串不满足长度限制,那么后面的必定也不满足长度限制

    具体原理请参考 KMP 的 (Next) 数组的原理

    最后再判断一下子串的相同前后缀长度是否满足大于 (K) 就好了

    Code

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #define maxn 1000010
    
    using namespace std;
    
    int Nxt[maxn],J,n,k;
    int ans;
    char s[maxn];
    
    int read(){
    	int s=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    	return s*w;
    }
    
    void Kmp(int Begin){
    	J=Begin-1;Nxt[Begin]=Nxt[Begin-1]=J;
    	for(int i=Begin;i<n;i++){
    		while(J>Begin-1&&s[J+1]!=s[i+1]) J=Nxt[J];
    		if(s[J+1]==s[i+1]) J++;
    		Nxt[i+1]=J;
    	}
    	for(int i=Begin;i<n;i++){
    		J=Nxt[i+1];//
    		while(J>Begin-1&&Begin+2*(J-Begin+1)>i+1) J=Nxt[J];//
    		if(J-Begin+1>=k) ans++;
    	}
    }
    
    int main(){
    	scanf("%s",s+1);k=read();
    	n=strlen(s+1);Nxt[0]=Nxt[1]=1;
    	for(int i=1;i<=n;i++) Kmp(i);
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    第三章 IP地址分类及其子网划分
    第二章 NFS简单实战教程
    第一章 Rsync实战教程
    第三章 struts2 (二)
    第二章 struts2入门
    第一章 struts2 入门
    《Python语言及其应用》学习笔记
    ASPX页面请求响应过程
    Python 对象(type/object/class) 作用域 一等函数 (慕课--Python高级,IO并发 第二章)
    javascript 运行机制 事件循环 浏览器缓存 (慕课网 前段跳槽面试必备 4-1,4-2,4-3)
  • 原文地址:https://www.cnblogs.com/KnightL/p/14248932.html
Copyright © 2020-2023  润新知