20-nuc-oj-白嫖怪Long Long

白嫖怪Long Long

问题描述

Long Long准备去吃串串,刚好发现串串店正在搞活动,只要能帮店主解决一个问题,这一顿就可以白嫖。作为白嫖怪,Long Long怎么能错过这次机会,但是他是一个字符串渣渣,现在需要你来帮他解决。由于他十分着急吃串串,他只给你1s的时间解决这个问题。

问题是这样的:店主十分喜欢回文串(正着读和反着读都一样的字符串),比如 “nucun”,“acmmca” 这样的都是回文串,现在店主随机给你出两个字符串a和b,如果b串是回文串,求出a串中b串出现的个数和出现的所有位置。要求你写一个程序可以解决所有这样的问题。

输入描述

第一行输入一个t,表示有t(1<=t<=10)组样例。

接下来有t组,每组输入两个字符串a和b,1<=|a|<=1000000, 1<=|b|<=1000000。

输出描述

对于每个样例,如果b串不是回文串输出一行"NO",否则输出一行"YES",并输出一个数m,表示b串在a串中出现了几次,接下来输出m行,按起始位置的字典序由小到大输出b串在a串出现的起始位置和终点位置。每个样例之间有一个空行。

样例输入

3
abbbabbbabbb
a
abba
abc
aaaa
aa

样例输出

YES
3
1 1
5 5
9 9

NO

YES
3
1 2
2 3
3 4

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int N = 1e6+10;
int a[N];
int ne[N];
char p[N];
char s[N];
int n, m;
void init()
{
	for(int i=2, j=0; i<=m; i++)
	{
		while(j && p[i] != p[j+1])
		{
			j = ne[j];
		}
		if(p[i] == p[j+1])
			j++;
		ne[i] = j;	
	}
	for(int i=n; i>=1; i--)
	{
		s[i] = s[i-1];
	}
	for(int i=m; i>=1; i--)
	{
		p[i] = p[i-1];
	}
}

bool fan(int l)
{
	int res = l / 2;
	for(int i=1; i<=res; i++)
	{
		if(p[i] != p[l-i+1])
		{
			return false;
		}
	}
	return true;
}

int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		memset(ne, 0, sizeof ne);
		scanf("%s", &s);
		scanf("%s", &p);		
		int cnt = 0, k = 0;
		n = strlen(s);
		m = strlen(p);
		init();
		if(!fan(m))
		{
			puts("NO");
			if(t)
			{
				puts("");
			}
			continue;
		}
		for(int i=1, j=0; i<=n; i++)
		{
			while(j && s[i] != p[j+1])
			{
				j = ne[j];
			}
			if(s[i] == p[j+1])
			{
				j++;
			}
			if(j == m)
			{
				j = ne[j];
				cnt++;
				a[k++] = i - m + 1;
				a[k++] = i;
				i = i - m + 1;
			}
		}
		puts("YES");
		printf("%d\n", cnt);
		for(int i=0; i<k; i+=2)
		{
			printf("%d %d\n", a[i], a[i+1]);
		}
		if(t)
		{
			puts("");
		}
	}
	return 0;
}

KMP算法板子题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值