[NOIP2017模拟]Bovine Genomics

来源:互联网 发布:换手机登陆淘宝账号 编辑:程序博客网 时间:2024/06/06 03:04

题目描述
农夫约翰最近发现他的有些奶牛会画画,刚刚学完小学生物的他立刻开始研究起了这些奶牛的 DNA。
具体的,约翰有 N 头会画画的奶牛,N 头不会画画的奶牛,这些奶牛的 DNA 可以用 M 个字符来描述,每个字符是 A、C、G、T中的一个
比如说以下是 N=3,M=8 的一个示例:
位置: 1 2 3 4 5 6 7 8(哎呀对歪了)

会画画的牛 1: A A T C C C A T
会画画的牛 2: A C T T G C A A
会画画的牛 3: G G T C G C A A

不会画画的牛 1: A C T C C C A G
不会画画的牛 2: A C T C G C A T
不会画画的牛 3: A C T T C C A T

约翰发现,他只需要看[2,5]这个区间的 DNA就可以知道一头牛会不会画画(也就是说,没有一头会画画的牛的这个区间的 DNA是和某一头不会画画的牛的这个区间的 DNA相同的),他相信一头牛是否会画画是由这个区间的 DNA决定的,他称这样的区间为“决定区间”。
现在给你所有牛的 DNA,求最短的决定区间的长度。

输入格式
第一行两个数 N,M(N<=500;M<=500)。
接下来N 行,每行 M个字符,描述 N 头会画画的牛的DNA。
接下来N 行,每行 M个字符,描述 N 头不会画画的牛的 DNA。

输出格式
输出最短的决定区间的长度。

样例数据
输入
3 8
AATCCCAT
ACTTGCAA
GGTCGCAA
ACTCCCAG
ACTCGCAT
ACTTCCAT
输出
4

备注
【数据范围】
40% 的数据:N,M<=100。
100% 的数据:N,M<=500。

分析:数据很小,二分枚举长度,然后在每一只牛的DNA中从头开始截取这么长,把会画画的丢进哈希表,用不会画画的去匹配,如果满足没有一个相同的就返回true,继续二分找更短的;不然依次平移一个字符再次计算,如果到最后都没有满足false,就返回,继续二分找更长的。(hash差不多忘光了,回头写个hash总结吧)

代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;int getint(){    int sum=0,f=1;    char ch;    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());    if(ch=='-')    {        f=-1;        ch=getchar();    }    for(;ch>='0'&&ch<='9';ch=getchar())        sum=(sum<<3)+(sum<<1)+ch-48;    return sum*f;}const int N=505;const long long p=31,H=23333;//听说进制用31进制最佳(听说而已),但是23333是质数这是真的!int n,m,ans,tot,hash[H],nxt[N];unsigned long long mi[N],num[N<<1][N],val[N*N];char s[N<<1][N];void prework(){    mi[0]=1;    for(int i=1;i<=m+1;++i)        mi[i]=mi[i-1]*p;    for(int i=1;i<=n*2;++i)        for(int j=1;j<=m;++j)            num[i][j]=num[i][j-1]*p+s[i][j]-'A'+1;}void insert(unsigned long long x){    int y=x%H;    for(int v=hash[y];v;v=nxt[v])        if(val[v]==x)            return;    nxt[++tot]=hash[y];    hash[y]=tot;    val[tot]=x;}bool find(unsigned long long x){    long long y=x%H;    for(int v=hash[y];v;v=nxt[v])        if(val[v]==x)            return true;    return false;}bool check(int len){    unsigned long long x;    for(int i=1;i<=m-len+1;++i)//在DNA中依次平移    {        memset(hash,0,sizeof(hash));        tot=0;        int bz=1;        for(int j=1;j<=n;++j)//把会画画的整个一段丢进hash表        {            x=num[j][i+len-1]-num[j][i-1]*mi[len];            insert(x);        }        for(int j=n+1;j<=2*n;++j)//用不会画画的这一段去匹配        {            x=num[j][i+len-1]-num[j][i-1]*mi[len];            if(find(x))            {                bz=0;                break;            }        }        if(bz)            return true;    }    return false;}int main(){    freopen("cownomics.in","r",stdin);    freopen("cownomics.out","w",stdout);    int len;    unsigned long long x;    n=getint();m=getint();    for(int i=1;i<=n*2;++i)        scanf("%s",s[i]+1);    prework();    int l=1,r=m;    while(l<=r)//二分查找    {        int mid=l+r>>1;        if(check(mid))            r=mid-1;        else            l=mid+1;    }    cout<<l<<endl;    return 0;}

本题结