[BalticOI 2014 Day1] Three Friends

原题链接

Title

一个字符串被复制加倍了一遍后,被插入一个字符,求原来的字符串。

Solution

由于被复制了一遍,还被加入了一个字符,所以最后的字符数量一定可以表示为 \(2n+1\),即奇数。如果不是奇数,直接输出无解。
然后把字符串分为前后半段,令 \(mid=n/2+1\)。然后分别讨论插入字符在前半段还是后半段即可。
如果在前半段,那么后半段就是原字符,然后在前半段枚举插入位置,然后用 hash 去比较。后半段同理。
对于怎么处理去掉插入位置的哈希值,比如字符串 abcde,要去掉 c,则我们分别取出 abde,然后把 de 丢后面,再加上 \(ab\times K^2\),因为 ab 要往前移 \(2\) 位,其中 \(K\) 是你 hash 的进制数。
然鹅对于下面一组数据:

AAAAAAA

正确答案应为 AAA,而我们会判多解,因为我们枚举会重复。
用 hash 表判重即可。

Code

#include<bits/stdc++.h>
#define ud unsigned 
#define int long long
using namespace std;
const int N=2e6+7;
const ud K=233;
char s1[N],s2[N];
ud g[N],po[N];
int pre[N],now[N],son[N],tot;
ud get(char *s,int n)
{
	ud ans=0;
	for(int i=1;i<=n;i++)
		ans=ans*K+s[i];
	return ans;
}
void Get(char *s,int n)
{
	for(int i=1;i<=n;i++)
		g[i]=g[i-1]*K+s[i];
}
void add(ud b)
{
	int a=b%100001;
	pre[++tot]=now[a];
	son[tot]=b;
	now[a]=tot;
}
bool find(ud b)
{
	int a=b%100001;
	for(int p=now[a];p;p=pre[p])
		if(son[p]==b)return 1;
	return 0;
}
ud gethash(int l,int r)
{return g[r]-g[l-1]*po[r-l+1];}
ud sum(int l,int r,int k)
{return gethash(l,k-1)*po[r-k]+gethash(k+1,r);}
int st[N],cnt;
main()
{
	po[0]=1;
	for(int i=1;i<=2e6+1;i++)po[i]=po[i-1]*K;
	int n;
	scanf("%lld%s",&n,s1+1);
	Get(s1,n);
	if(n%2==0){printf("NOT POSSIBLE");return 0;}
	int mid=n/2+1,ans=0,k;
	for(int i=1;i<=mid;i++)
	{
		int k1=gethash(mid+1,n);
		int k2=sum(1,mid,i);
		if(k1==k2)
		{
			if(find(k1))continue;
			add(k1);ans++;k=1;
		}
	}
	for(int i=mid+1;i<=n;i++)
	{
		int k1=gethash(1,mid-1);
		int k2=sum(mid,n,i);
		if(k1==k2)
		{
			if(find(k1))continue;
			add(k1);ans++;k=2;
		}
	}
	if(ans>1)printf("NOT UNIQUE");
	else if(ans==1)
	{
		if(k==1)
		for(int i=mid+1;i<=n;i++)
			cout<<s1[i];
		else
		for(int i=1;i<=mid-1;i++)
			cout<<s1[i];	
	}
	else printf("NOT POSSIBLE");
	return 0;
}
posted @ 2022-07-11 18:02  Epoch_L  阅读(23)  评论(0编辑  收藏  举报