UVALive 8331 Mars

对于询问为长度为len的字符串,原字符串中长度为len的字符串一共只有n-len+1个,所以字符串hash以后最多有n-len+1个字符串的不同数值,而且询问字符串任意变异类型,字符串一定是不一样的,所以可以放心大胆dfs,dfsn-len+1次以后,一定就能找到,要么就没有n-len+1那么多种变异,就有可能为impossible。

以前TB说过字符串hash直接用两个大素数进行%,然后set存起来,还说bzoj上专门有这样的一个题让你出数据卡他,至今AC未0,所以保存对两个大素数取模的hash值是非常唯一的,几乎不可能重合,不然就公共溢出区(qt数组版不要用vector,很慢很容易爆空间),或者开放寻址法。

然而这道题不知道为撒一直A不了,看了其他人的代码发现可以直接一个素数取模,甚至不用冲突处理。。。数据有点水,然而这样写又因为ans没有初始化导致疯狂WA。。。。我真是去一头撞死算了,上次第一次打cfdiv1,A题因为开小数组,WA了一发,然后过了6分钟才发现开小数组。。。光速掉会蓝名,我这个学期的离散和高数也是,各种奇怪出错,什么时候才能减少粗心出错啊。。。什么long long ,初始化,数组大小,输出格式,i写成l,取模负数没处理。都WA过无数次了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#define maxl 10010
#define mod 12255871

using namespace std;

int n,m,len,h;
char s[maxl];
int a[maxl],b[maxl],ans[maxl];
int mi[maxl],c[maxl];
struct query
{
	int a,b,ind;
}q[1010];
bool flag;
bool vis[maxl];
set <int> P;
bool cmp(const query &x,const query &y) 
{
	return (x.b-x.a+1)<(y.b-y.a+1);
}

inline void prework()
{
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
		a[i]=s[i]-'0';
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&q[i].a,&q[i].b);
		q[i].ind=i;	
	}
	sort(q+1,q+1+m,cmp);
}

inline void init(int l)
{
	for(int i=1;i<=c[0];i++)
		P.erase(c[i]);
	P.clear();
	c[0]=0;
	int num=0;
	for(int i=1;i<=l;i++)
		num=((num<<1)+a[i])%mod;
	P.insert(num);
	c[++c[0]]=num;
	for(int i=l+1;i<=n;i++)
	{
		num=(num-a[i-l]*mi[l-1]+mod)%mod;
		num=((num<<1)+a[i]+mod)%mod;
		c[++c[0]]=num;
		P.insert(num);
	}
}

void dfs(int k,int last,int num)
{
	if(k==h)
	{
		if(P.find(num)==P.end())
			flag=true;
		return;
	}
	int lastnum=num;
	for(int i=last+1;i<=len-h+k+1 && !flag;i++)
	if(!vis[i])
	{
		vis[i]=true;
		num=(num-mi[len-i]*b[i])%mod;
		num=(num+mod)%mod;
		num=(num+mi[len-i]*(b[i]^1))%mod;
		dfs(k+1,i,num);
		num=lastnum;
		vis[i]=false;
	}
}

inline void mainwork()
{
	int num;
	q[0].a=1;q[0].b=0;
	for(int i=1;i<=m;i++)
	{
		if(q[i].b-q[i].a+1!=q[i-1].b-q[i-1].a+1)
			init(q[i].b-q[i].a+1);
		for(int j=q[i].a;j<=q[i].b;j++)
			b[j-q[i].a+1]=a[j];
		flag=false;
		len=q[i].b-q[i].a+1;
		memset(vis,false,sizeof(vis));
		num=0;
		for(int j=1;j<=len;j++)
			num=((num<<1)+b[j])%mod;
		for(int j=1;j<=n && !flag;j++)
		{
			h=j;
			dfs(0,0,num);
			if(flag)
			{
				ans[q[i].ind]=j;
				break;
			}
		}
		if(!flag)
			ans[q[i].ind]=0;
	}
	
}

inline void print()
{
	for(int i=1;i<=m;i++)
	if(ans[i])
		printf("%d\n",ans[i]);
	else
		printf("Impossible\n");

}

int main()
{
	mi[0]=1;
	for(int i=1;i<maxl;i++)
		mi[i]=(mi[i-1]<<1)%mod;
	while(~scanf("%d%d",&n,&m))
	{
		if(n==0 && m==0)
			break;
		prework();
		mainwork();
		print();
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值