专栏文章

自测题目solution(NO CTJ)

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minje1ze
此快照首次捕获于
2025/12/02 03:23
3 个月前
此快照最后确认于
2025/12/02 03:23
3 个月前
查看原文

主题思路

如果把‘相同’当作完全相同,则这就是一个 KMP 板子,所以我们主要是要知道如何判断两个字符是 相同的

如何判相同

我们定义两个数组 s,t,表示当前字符对应的最近的上一个字符的距离,如abcab00033,(这里仅是示例),我们可以观察到如果两个字符串是‘相同的’,则它们按这个规则组成的数组也一定相等\color {white} 吗
有一种特殊情况,比如ababbcdd。这时两个分别为00221001,所以需要特判是否在比较范围内,及 KMP 时的 j.

code

CPP
#include<bits/stdc++.h>
using namespace std;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
const int N=1e6+5;
int Q;
int n,m;
int pre[N];
int s[N],t[N];
int nxt[N];
string S,T;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
bool cmp(int x,int y,int len){//compare between x and y
	if(x<0 && y<0) return x==y;
	return x==y || (y==0 && x>len);
}
void KMP(){
	memset(nxt,0,sizeof nxt);
	nxt[1]=0;
	int ans=0;
	for(int i=2,j=0;i<=m;i++){
		while(j && !cmp(t[i],t[j+1],j)) j=nxt[j];
		if(cmp(t[i],t[j+1],j)) j++;
		nxt[i]=j;
	}
	for(int i=1,j=0;i<=n;i++){
		while(j && !cmp(s[i],t[j+1],j)) j=nxt[j];
		if(cmp(s[i],t[j+1],j)) j++;
		if(j==m) ans++,j=nxt[j];
	}
	cout<<ans<<'\n';
}
void solve(){
	getline(cin,S);
	getline(cin,T);
	//while(S.size() && S.back()<30) S.pop_back();
	//while(T.size() && T.back()<30) T.pop_back();
	n=S.size(),m=T.size();
	S='%'+S,T='%'+T;
	memset(pre,0,sizeof pre);
	for(int i=1;i<=n;i++){//Do with S
		if(S[i]>='a'&&S[i]<='z'&&S[i]!='i'&&S[i]!='n'&&S[i]!='t'){
			if(pre[S[i]-'a'+1]>0) s[i]=i-pre[S[i]-'a'+1];
			else s[i]=0;
			pre[S[i]-'a'+1]=i;
		}else s[i]=-S[i];
	}
	memset(pre,0,sizeof pre);
	for(int i=1;i<=m;i++){//Do with T
		if(T[i]>='a'&&T[i]<='z'&&T[i]!='i'&&T[i]!='n'&&T[i]!='t'){
			if(pre[T[i]-'a'+1]>0) t[i]=i-pre[T[i]-'a'+1];
			else t[i]=0;
			pre[T[i]-'a'+1]=i;
		}else t[i]=-T[i];
	}
	KMP();
}
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
signed main(){
	freopen("ctj.in","r",stdin);
	freopen("ctj.out","w",stdout);
	cin>>Q;
	getline(cin,S);
	while(Q --> 0) solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...