LibreOJ #10047

應同機房某大佬的要求來寫這篇題解ios

Description

給定一個字符串 \(S\) 和一個數 \(K\),要求求出 \(S\) 的全部形似 \(A+B+A\) 的子串數量,其中 \(\mid A\mid \ge K\)\(\mid B\mid \ge 1\)數組

位置不一樣其餘性質相同的子串算不一樣子串,位置相同但拆分不一樣的子串算同一子串spa

Solution

\(S\) 的長度爲 \(n\)code

對於 \(S\)\(1\)\(n\) 的每個位置,以當前位置的字符做爲一個子串的起點,而後尋找它的終點,來肯定當前子串是否知足條件ip

對於 \(Next\) 數組的預處理仍是相同操做,可是每換一個起點就要從新處理一次,只處理從當前位置到最後的字符字符串

對於每一個子串的終點,能夠發現,只要在知足總長度的狀況下不停回溯,才能統計全部的狀況get

回溯到最後的位置就是與它相同的最初子串的結束位置,由於不一樣位置相同子串算做同一子串,因此遇到相同的時,回溯到第一個相同子串即可統計string

同理,若第一個相同子串不知足長度限制,那麼後面的一定也不知足長度限制io

具體原理請參考 KMP 的 \(Next\) 數組的原理class

最後再判斷一會兒串的相同先後綴長度是否知足大於 \(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;
}
相關文章
相關標籤/搜索