CF727E. Games on a CD (Hash)

题目链接:https://acm.njupt.edu.cn/problem/CF727E
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
题意:题目我看了好久才看懂,意思是将输入的第二行的字符串围成一个圆(首尾相连),可以从圆的任意位置剪开让它成为一个新的字符串,这个新的字符串必须用给出g个字符串来拼凑出(g个字符串不一定要全有,但只能有这g个字符串之中的字符串)。
解题思路:令第二行输入字符串为str,g行输入的为s
1.解决圆的问题,直接在str后面在添上str[0~1]这个区间的字符就行。
2.先对str进行hash,再对g个字符串s进行分别hash并保存。
3.然后开始遍历for(int i=1;i<=k;i++),为什么上界在k?因为在k+1位置处和1位置处是相同的,然后依次保存str的k长度子字符串的Hash值,保存到set数组中,(这里要注意判断不满足条件,该Hash值在set中已经存在或者该Hash值在g个字符串中不存在,这时候就是不满足的情况),如果条件可以满足并且set数组中size=n,则满足,直接输出就行。
注意点:
1.利用双哈希,防止巧合导致重复
2.利用双哈希时候,用pair<ll,ll>来保存每个状态(我使用了结构体node,node里面是两个ll,会导致报错)

#include<iostream>
#include<cstdio>
#include<set>
#include<map>
using namespace std;
#define ll unsigned long long
const int mod1 =1e9+7;
const int mod2 =1e9+9;
const int p =131;
typedef pair<ll,ll> P;
map<P ,int> m;
set<int> se;
ll Hash1[2000000],Hash2[2000000];
int n,k,g;
int len1,len2;
ll Pow1,Pow2;
int ans[2000000];
char s1[2000000];
char s2[2000000];
ll cmp_hash1(int l,int r)
{
	return (Hash1[r]+mod1-Hash1[l-1]*Pow1%mod1)%mod1;
}
ll cmp_hash2(int l,int r)
{
	return (Hash2[r]+mod2-Hash2[l-1]*Pow2%mod2)%mod2;
}
void Init()
{
	Pow1=1; Pow2=1;
	for(int i=1;i<=k;i++)
		Pow1=Pow1*p%mod1,Pow2=Pow2*p%mod2;
	for(int i=1;i<=len1+k;i++)
	{
		if(i>len1)
			s1[i]=s1[i-len1];
		Hash1[i]=(Hash1[i-1]*p+(s1[i]-'a'+1))%mod1;
		Hash2[i]=(Hash2[i-1]*p+(s1[i]-'a'+1))%mod2;
	}
	len1=strlen(s1+1);
	for(int i=1;i<=g;i++)
	{
		scanf("%s",s2+1);
		len2=strlen(s2+1);
		ll res1=0,res2=0;
		for(int j=1;j<=len2;j++)
		{
			res1=(res1*p+(s2[j]-'a'+1))%mod1;
			res2=(res2*p+(s2[j]-'a'+1))%mod2;
		}
		P temp;
		temp.first=res1;
		temp.second=res2;
		m[temp]=i;
	}
}
int main()
{
	cin>>n>>k;
	scanf("%s",s1+1);
	len1=strlen(s1+1);
	cin>>g;
	Init();
	for(int i=1;i<=k;i++)
	{
		se.clear();
		for(int j=i;j<i+n*k;j+=k)
		{
			ll res1=cmp_hash1(j,j+k-1);
			ll res2=cmp_hash2(j,j+k-1);
			P temp;
			temp.first=res1;
			temp.second=res2;
			if(m.find(temp)==m.end()||se.find(m[temp])!=se.end())
				break;
			ans[(j-i)/k+1]=m[temp];
			se.insert(m[temp]);
		}
		if(se.size()==n)
		{
			cout<<"YES"<<endl;
			for(int j=1;j<=n;j++)
				printf("%d ",ans[j]);
			return 0;
		}
	}
	cout<<"NO"<<endl;
	return 0;
}
原创文章 65 获赞 3 访问量 2108

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/104877623
cd
今日推荐