kmp——可爱即正义

kmp——可爱即正义

题目描述

小可爱是个可爱的女孩子(nzdl)。
众所周知,小可爱在物竞初赛时候有两道大题没有做出来,所以,可爱的小可爱(qwq)便沉浸在了毒瘤之中——无法接受在任何地方看到"suqingnianloveskirito"这个东西。然而,这时候从SD某处送来了一封安慰信(情书),信的内容是一个26个小写拉丁字母组成的字符串s。这封信提前被wyxdrqc劫了下来(没错,就是这个劫),他打开了这封信,结果发现了满篇的"suqingnianloveskirito"所以他想篡改这封信。
由于他的能力有限,所以他只能把这个字符串的其中两个位置上的字符互换,而且只能操作一次。
他现在想问你,通过他的操作能不能使"suqingnianloveskirito"不是这个字符串的子串。

输入描述

一行一个字符串 s。

输出描述

如果他能通过只交换其中的两个位置上的字符使"suqingnianloveskirito"不是交换后的字符串的子串,则在第一行输出一个Yes,之后一行输出两个数d1,d2,表示你的方案是把原字符串在位置d1和位置d2上的字符互换,字符串的第一个字符的位置是1。
如果他不管交换那两个字符都不能满足条件,直接输出一行No。

示例 1

输入

suqingnianloveskiritosuqingnianloveskiritosuqingnianloveskiritothemostimportantthingneedsaidatleastthreetimes

输出

No

示例 2

输入

suqingnianloveskiritosomuch

输出

Yes
1 2

备注

对于 100% 数据,有字符串的长度 <= 1000000
对于 10% 数据,有测试数据的答案 = 样例。
并且你的方案中,不能出现 d1 = d2 的情况。
如果有多种可行方案,输出任何一种即可得分。

#include<bits/stdc++.h>
using namespace std;
const int N = 1000005;
string t,s;
int nxt[N],f[N],a,b;

void getNext()
{
	int slen=s.length();
	int j=0;
	int k=-1;
	nxt[0]=-1;
	while(j<slen){
		if(k==-1||s[j]==s[k]){
			++k;
			++j;
			nxt[j]=k;
			f[k]++;
		}
		else{
			k=nxt[k];
		}
	}
}

int kmp()
{
	int i=0;
	int j=0;
	int tlen=t.length();
	int slen=s.length();
	int flag=0;
	while(i<tlen){
		if(j==-1 || t[i]==s[j]){
			i++;
			j++;
		}
		else{
			j=nxt[j];
		}
		if(j==slen){
			flag++;
			j=nxt[j];
			if(flag==1){
				a=i-slen;
			}
			if(flag==2){
				b=i-slen;
			}
		}
	}
	return flag;
}

int main()
{
	cin>>t;
	s="suqingnianloveskirito";
	if(t.size()<s.size()){		// 当输入字符串长度小于字符串 s 的长度时,能够满足条件 
		cout<<"Yes"<<endl;
		cout<<1<<" "<<2<<endl;
	}
	else{
		getNext();
		int n=kmp();
		if(n>2){		// 如果输入的字符串中存在两个以上子串与字符串 s 匹配,则不能满足条件 
			cout<<"No"<<endl;
		}
		else if(n==2){		// 当输入的字符串存在两个子串与字符串 s 匹配时,能够满足条件 
			cout<<"Yes"<<endl;
			cout<<a+1<<" "<<b+2<<endl;
		}
		else{			// 当输入的字符串只存在一个子串与字符串 s 匹配时,能够满足条件 
			cout<<"Yes"<<endl;
			cout<<a+1<<" "<<a+2<<endl;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值