Mars UVALive - 8331 (Hash+DFS)

A new form of life is recently discovered on Mars. Every alien has a DNA, that is a string with an alphabet of only two, rather than four, letters. Hence we can show the DNA of a Mars alien by a binarystring. Let s be an alien DNA of length n. There are q regions in the DNA specified as genes. A genelocated at [a, b] is a substring of the DNA, containing characters from position a to position b, inclusive(1 ≤ a ≤ b ≤ n). A gene might overlap with or be inside the other genes.

During the life of a Mars alien, each gene is copied billions of times: a protein binds to the start of the gene, and copies the gene from start to the end. But this process is not error-free, and might produce mutations. In each mutation, a 0 in the gene is copied as 1, or vice-versa. A mutated copy does not match the gene, but might match a (possibly overlapping) substring in another position of theDNA. For instance, assume that s = 001011111 and a gene is located at [3, 6]. Hence, the gene stringis “1011”. A copy of this gene can be “1111”, which is mutated at the second letter. Although “1111”does not match the original [3, 6] substring in the DNA, it matches [5, 8]. A mutated copy of a geneis called degenerate if it does not appear in any place of the whole DNA. Hence, “1010”, a copy of thesame gene having one mutation at the fourth letter, is degenerate, but “1111” is not.

Your task is to find, for each gene, the minimum number of mutations that can result in a degenerate 
copy of that gene. 
Input 
There are multiple test cases in the input. The first line of each test case contains two integers n and 
q (2 ≤ n ≤ 10, 000 and 1 ≤ q ≤ 1000). The next line contains a binary string s of length n. Each of 
the next q lines contains the location [a, b] of a gene, in the form of two space-separated integers a and 
b (1 ≤ a ≤ b ≤ n). 
The input terminates with a line containing ‘0 0’ that should not be processed. 
Output 
For each gene, print the minimum number of mutations that can result in a degenerate copy. If no set 
of mutations applied on a gene can result in a degenerate copy, print ‘Impossible’ instead. 
Sample Input 
4 3 
0110 
1 2 
2 3 
1 1 
0 0 
Sample Output 


Impossible

反正我也是写过一次了,但是csdn出bug了就没了。但是卡了16个小时写出来,还是值得我再写一次博客的

题目大意:

给出一条长度为n的01串,给出q个询问,每次询问一个子串至少需要改变多少次才能走在原串中找不到。

思路:

预处理出和询问子串长度相同的所有子串的哈希值,对子串进行DFS直至子串的哈希值无法在哈在原串子串的哈希值中找到

考虑到其余子串最多有n-len种情况,所以每次dfs的询问至多有min(n-len,2^len)次运算。考虑最坏情况大约会询问10000次,乘上1000,也就是10^7操作,时间上是没有问题的。

提两个决定性的优化:

1、先读取全部的询问,对于长度相同的询问只预处理一次,避免重复的计算

2、dfs尽量减少对没有01翻转不变化的情况的计算可以减少很多计算量

决定这个题目的时间的主要有两个点,一个是dfs的方式这点很重要,我学长的dfs方式只用了859ms,但是我的就用了2976ms,可见还是很重要的,还有就是Hash的方式,推荐使用自然溢出的方式取模这样可以快不少。

代码:

垃圾DFS,2976ms:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<unordered_map> 
#define endl '\n'
#define sc(x) scanf("%d",&x)

using namespace std;
typedef unsigned long long ULL;
const ULL mod=133333;
const int inf=0x3f3f3f3f;
const int size=1e4+5;
const int maxn=1005;
char s[size];
int ans[maxn];
ULL H[size],P[size];
unordered_map<ULL,bool> mp;
int s_len;
struct node{
	int l,r,len;
	int id;
	void getlen()
	{
		len=r-l+1;
	}
	bool operator<(const node& a)const
	{
		return len<a.len;
	}
}query[maxn];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void first_init()
{
	P[0]=1;
	for(int i=1;i<=10004;i++)
	{
		P[i]=P[i-1]*mod;
	}
}
void Hash()
{
	H[0]=0;
	for(int i=1;i<=s_len;i++)
	{
		H[i]=H[i-1]*mod+s[i]-'0';
	}
}
inline ULL code(int l,int r)
{
	return H[r]-H[l-1]*P[r-l+1];
}
int dfs(int l,int r,int dep,ULL str,int cnt)
{
	int b;
	if(!mp.count(str)) return cnt;//如果成功得到串优先进行此判断 
	if(l+dep==r+1) return inf;//如果已经到了最后一位仍然没能成功退化,就返回不行 
	int ans=inf;
	for(int i=dep;i+l<=r;i++)
	{
		ULL t=str+(s[l+i]=='0'?P[r-l-i]:-P[r-l-i]);
		b=dfs(l,r,i+1,t,cnt+1);//变
		ans=min(b,ans);
	}
	
	return ans;
}
inline void pre_solve(int len)
{	
	mp.clear();
	for(int i=1;i+len-1<=s_len;i++)
	{
		mp[code(i,i+len-1)]=true;
	}
}
int main()
{
	int q;
	first_init();
	while(~scanf("%d%d",&s_len,&q)&&(s_len||q))
	{
		scanf("%s",s+1);
		Hash();
		for(int i=0;i<q;i++)
		{
			query[i].l=read(),query[i].r=read();
			query[i].getlen();
			query[i].id=i;
		}
		sort(query,query+q);
		for(int i=0;i<q;i++)
		{
			int R=query[i].r,L=query[i].l;
			if(i>0&&query[i].len!=query[i-1].len)
			pre_solve(R-L+1);
			if(i==0)pre_solve(R-L+1);
			ans[query[i].id]=dfs(L,R,0,code(L,R),0);
		}
		for(int i=0;i<q;i++)
		{
			if(ans[i]==inf) cout<<"Impossible"<<endl;
			else cout<<ans[i]<<endl;
		}	
	}
	return 0;
}

优秀的DFS 859ms

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<unordered_map> 
#define endl '\n'
#define sc(x) scanf("%d",&x)

using namespace std;
typedef unsigned long long ULL;
typedef long long LL; 
const ULL mod=133333;
const int size=1e4+5;
const int maxn=1005;
char s[size];
int ans[maxn];
ULL H[size],P[size];
unordered_map<ULL,bool> mp;
int s_len;
struct node{
	int l,r,len;
	int id;
	void getlen()
	{
		len=r-l+1;
	}
	friend bool operator<(node a,node b)
	{
		return a.len<b.len;
	}
}query[maxn];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void first_init()
{
	P[0]=1;
	for(int i=1;i<=10004;i++)
	{
		P[i]=P[i-1]*mod;
	}
}
void Hash()
{
	H[0]=s_len;
	for(int i=1;i<=s_len;i++)
	{
		H[i]=H[i-1]*mod+s[i]-'0'+1;
	}
}
inline ULL code(int l,int r)
{
	return H[r]-H[l-1]*P[r-l+1];
}
int dfs(int l,int r,int cnt,ULL str)
{
	if(!cnt) return mp[str];
	for(int i=l;i<=r;i++)
	{
		int tmp=s[i]-'0';
		ULL t=str-P[r-i]*(1+tmp)+P[r-i]*(2-tmp);
		if(!dfs(i+1,r,cnt-1,t)) return 0;
	}
	return 1;
}
inline void pre_solve(int len)
{	
	mp.clear();
	for(int i=1;i+len-1<=s_len;i++)
	{
		mp[code(i,i+len-1)]=true;
	}
}
int main()
{
	int q;
	first_init();
	while(~scanf("%d%d",&s_len,&q)&&s_len)
	{
		scanf("%s",s+1);
		Hash();
		for(int i=0;i<q;i++)
		{
			query[i].l=read(),query[i].r=read();
			query[i].getlen();
			query[i].id=i;
			ans[i]=-1;
		}
		sort(query,query+q);
		for(int i=0;i<q;i++)
		{
			int R=query[i].r,L=query[i].l;
			if(i>0&&query[i].len!=query[i-1].len)	pre_solve(R-L+1);
			if(i==0)	pre_solve(R-L+1);
			LL cnt=1,pre=R-L+1;
			for(int len=1;len<=R-L+1;len++)
			{
				if(!dfs(L,R,len,code(L,R))) {ans[query[i].id]=len;break;}
				if(len==R-L+1) break;
				cnt+=pre;
				pre=pre*(query[i].len-len)/(len+1);
				if(cnt+pre>s_len-query[i].len+1) ans[query[i].id]=len+1; 
			}
		}
		for(int i=0;i<q;i++)
		{
			if(ans[i]==-1) cout<<"Impossible"<<endl;
			else cout<<ans[i]<<endl;
		}	
	}
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值