CSU 2037 Mars(后缀自动机+DFS)

2037: Mars

Submit Page    Summary    Time Limit: 3 Sec     Memory Limit: 512 Mb     Submitted:64     Solved:16    

Description

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 binary string. Let s be an alien DNA of length n. There are q regions in the DNA specified as genes. A gene located 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 the DNA. For instance, assume that s = 001011111 and a gene is located at [3, 6]. Hence, the gene string is 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 gene is called degenerate if it does not appear in any place of the whole DNA. Hence, 1010, a copy of the same 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

1
2
Impossible

Hint

Source

ATRC2017


       大致题意,给你一个01字符串,然后再给你这个字符串的一个子串,问你在子串中至少修改多少个字符,才能够使得修改之后的串在原串中不出现。
       现场拿到题就知道一定是SAM后缀自动机。因为要求是某一个串在原串中不出现,也就是某个串不是原串的子串,所以我们显然要知道做到判定串是否是子串。纵观比较高效的数据结构,也就只有后缀自动机了。我们首先对原串建立自动机,然后利用是01串的性质,对照给出串的每一位,分别dfs每一位是与原来相同,还是不同,相同不需要代价,不相同则需要代价。枚举了下一位的数字就可以顺着自动机跑,发现没有后继边是退出并比较结果。常用剪枝就是看当前代价是否已经大于等于最优代价,等于则退出。
       下面进入复杂度分析。空间上由于是后缀自动机,所以空间复杂度就是建立自动机的复杂度,O(N)。时间上,主要的花费在于枚举,对于一个长度为N的01串, 但是由于我每一次都是在自动机上走,而且每次移动都是往自动机后面移动,所以说能够转移的状态局限在自动机的点数以内,再加上基本的剪枝,和题目本身并不会使程序搜索太深。因此对于一个长度为N的串,复杂度应该是可以降到O(N)。故总的复杂度就是O(QN)。
        好了,不XJB分析了,这题复杂度玄学,但是实际效果是220MS通过。如果有稳定复杂度的,欢迎讨论。具体见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<map>
#include<queue>
#define N 20010
using namespace std;

struct Suffix_Automation
{
	int tot,cur;
	struct node{int ch[2],len,fa;} T[N];
	void init(){cur=tot=1;memset(T,0,sizeof(T));}

	void ins(int x,int id)
	{
		int p=cur;cur=++tot;T[cur].len=id;
		for(;p&&!T[p].ch[x];p=T[p].fa) T[p].ch[x]=cur;
		if (!p) {T[cur].fa=1;return;}int q=T[p].ch[x];
		if (T[p].len+1==T[q].len){T[cur].fa=q;return;}
		int np=++tot; memcpy(T[np].ch,T[q].ch,sizeof(T[q].ch));
		T[np].fa=T[q].fa; T[q].fa=T[cur].fa=np; T[np].len=T[p].len+1;
		for(;p&&T[p].ch[x]==q;p=T[p].fa) T[p].ch[x]=np;
	}
} SAM;

struct node{int pos,t,i;};
char s[N],st[N];
int n,m,len,ans;

void dfs(int x,int pos,int t)
{
    if (t>=ans) return;
    if (x>=len) return;
    int ch=st[x]-'0';
    int nxt=SAM.T[pos].ch[ch];
    if (nxt==0) ans=min(ans,t);
           else dfs(x+1,nxt,t);
    nxt=SAM.T[pos].ch[ch^1];
    if (nxt==0) ans=min(ans,t+1);
           else dfs(x+1,nxt,t+1);

}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		SAM.init();
		if (n+m==0) break;
		scanf("%s",s);
		for(int i=0;s[i];i++)
			SAM.ins(s[i]-'0',i+1);
		while(m--)
		{
			int a,b;
			ans=0x3f3f3f3f;
			scanf("%d %d",&a,&b);
			len=b-a+1; a--; b--;
			for(int i=0;i<len;i++)
				st[i]=s[a+i];
            st[b-a+1]='\0';	dfs(0,1,0);
            if (ans==0x3f3f3f3f) puts("Impossible");
                            else printf("%d\n",ans);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值