“三个朋友”「BalticOI 2014 Day1 T2 Three Friends」题解

三个朋友(洛谷)
三个朋友(LibreOJ)

题目

题目描述

给定一个字符串S,先将字符串S复制一次(变成双倍快乐 ),得到字符串T,然后在T中插入一个字符,得到字符串U。
给出字符串U,重新构造出字符串S。
所有字符串只包含大写英文字母。

输入格式

第一行一个整数N,表示字符串U的长度。
第二行一个长度为N的字符串,表示字符串U。

输出格式

一行一个字符串,表示字符串S。

特别地:

  1. 如果字符串无法按照上述方法构造出来,输出NOT POSSIBLE;
  2. 如果字符串S不唯一,输出 NOT UNIQUE。

样例

样例1输入
7
ABXCABC
样例1输出
ABC
样例2输入
6
ABCDEF
样例2输出
NOT POSSIBLE
样例3输入
9
ABABABABA
样例3输出
NOT UNIQUE

数据范围

2 \leq N \leq 2000001

分析

这一道题要用 hash
为了减少hash冲突而*31。
因为S翻倍后要插入一个字符,所以始终是2n+1,也就是奇数,所以如果是偶数就输出NOT POSSIBLE,并结束。
插入的字符有2种情况:

  1. 插入的字符在前面一半之间,则S(也就是答案)就在后面一半,我们就在前面枚举字符的位置,然后根据 hash值来判断是否相等;
  2. 插入的字符在后面一半之间,则S(也就是答案)就在前面一半,我们就在后面枚举字符的位置,然后根据 hash值来判断是否相等;

AC代码+注释

#include<bits/stdc++.h>
using namespace std;

long long n,hash[2000005],s[2000005],sum=0,ans,x;
char u[2000005];
map<long long,bool> flag;

int main()
{
	scanf("%lld %s",&n,u);
	if(!(n%2))
	{
		printf("NOT POSSIBLE");
		return 0;
	}
	//因为S翻倍后要插入一个字符,所以始终是2n+1,也就是奇数,所以如果是偶数就输出NOT POSSIBLE,并结束
	s[0]=1;
	for(long long i=1;i<n;i++)
	{
		s[i]=s[i-1]*31;
		//*31是为了减少hash冲突
	}
	for(long long i=0;i<n;i++)
	{
		hash[i+1]=hash[i]*31+(long long)(u[i]-'A'+1);
	}
	x=n>>1;
	for(long long i=1;i<=x;i++)
	{
		if(hash[x+1]-hash[i]*s[x+1-i]+hash[i-1]*s[x+1-i]==hash[n]-hash[x+1]*s[x]&&!flag[hash[n]-hash[x+1]*s[x]])
		{
			sum++;
			//找到了插入的字符也就自然有一个答案 
			ans=i;
			flag[hash[n]-hash[x+1]*s[x]]=1;
			//为了后面不再重复找到,flag便置为1,后面便进不了循环
		}
	}
	//插入的字符在前面一半之间,则S(也就是答案)就在后面一半,我们就在前面枚举字符的位置,然后根据 hash值来判断是否相等; 
	if(hash[x]==hash[n]-hash[x+1]*s[x]&&!flag[hash[x]])
	{
		sum++;
		ans=x+1;
		flag[hash[x]]=1;
	}
	for(long long i=x+2;i<=n;i++)
	{
		if(hash[n]-hash[i]*s[n-i]+(hash[i-1]-hash[x]*s[i-1-x])*s[n-i]==hash[x]&&!flag[hash[x]])
		{
			sum++;
			ans=i;
			flag[hash[x]]=1;
		}
	}
	//在后面则相反 
	if(!sum)
	{
		printf("NOT POSSIBLE");
	}
	//没有答案输出NOT POSSIBLE
	else
	{
		if(sum>1)
		{
			printf("NOT UNIQUE");
		}
		//如果答案不唯一,输出NOT UNIQUE 
		else
		{
			if(ans<=x+1)
			{
				for(long long i=x+2;i<=n;i++)
				{
					printf("%c",u[i-1]);
				}
			}
			//如果ans比U的一半少就输出后面一半 
			else
			{
				for(long long i=0;i<x;i++)
				{
					printf("%c",u[i]);
				}
			}
			//否则相反 
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/cqbzybc20220707/article/details/107898130