CF858D Polycarp's phone book

博客食用效果更佳!

题目描述

有 n 个长度为 9 且只包含数字字符且 互不相同 的串。

需要对于每个串找到一个 长度最短 的识别码,使得这个识别码 当且仅当 为这个串的子串。

(1leq nleq7*10^4)

题解

虽然可以用map糊过,但我们选择字典树

考虑暴力,我们可以把所有子串插入字典树,然后暴力枚举

但这样空间不够

再想想优化,其实我们可以不用把每个子串都插入

只需要插入每个串的所有后缀

接着再枚举所有子串匹配即可

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int inf=0x7fffffff;
typedef long long ll;
#define maxn 5000005
char a[70009][10];
int n,root=1;
int p[70009];
int tr[maxn][10];
int vis[maxn];
bool buok[maxn];
int cnt=2;
bool tag=0;
int timemark=1;
void Add(int pos,int s,int t)
{
	int now=root;
	for(int i=s;i<=t;i++)
	{
		int x=a[pos][i]-'0';
		if(!tr[now][x])tr[now][x]=++cnt;
		if(!vis[now])vis[now]=timemark;
		else if(vis[now]!=timemark)buok[now]=1;
		now=tr[now][x];
	}
		if(!vis[now])vis[now]=timemark;
		else if(vis[now]!=timemark)buok[now]=1;
} 
int l=0;
bool Query(int pos,int s,int t)
{
	l=0;
	int now=root;
	for(int i=s;i<=t;i++)
	{
		int x=a[pos][i]-'0';
		p[++l]=x;
		now=tr[now][x];
		//cout<<x;
	}
	//cout<<endl;
	if(buok[now]==1)return 0;
	return 1;
}
signed main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",a[i]);
	}
	tag=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<9;j++)
		{
			Add(i,j,8);
		}
		timemark++;
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<9;j++)
		{
			bool flag=0;
			for(int k=0;k+j<9;k++)
			{
				if(Query(i,k,k+j))
				{
				//	cout<<"I:"<<i<<endl;
					for(int q=1;q<=l;q++)printf("%d",p[q]);
					printf("
");
					flag=1;
					break;
				}
			}
			if(flag)break;
		}
	}
	 
	return 0;
}
原文地址:https://www.cnblogs.com/lzy-blog/p/15144635.html