题目描述
农夫约翰最近发现他的有些奶牛会画画,刚刚学完小学生物的他立刻开始研究起了这些奶牛的 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;
}
本题结