题解:P3763 [TJOI2017] DNA
Stars_visitor_tyw · · 题解
P3763 [TJOI2017] DNA 题解
分析
模拟赛没细想打了暴力。
暴力思路就是枚举起点以及遍历
暴力代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
// freopen("T4.in","r",stdin);
// freopen("T4.out","w",stdout);
ios::sync_with_stdio(0);
int t;
for(cin>>t;t;t--)
{
string a, b;
cin>>a>>b;
int n=a.size(), m=b.size();
a=" "+a;
b=" "+b;
int ans=0;
for(int i=1;i<=n-m+1;i++)
{
int cnt=0;
for(int j=1;j<=m;j++)
{
if(a[i+j-1]!=b[j])
{
cnt++;
}
if(cnt>3)break;//优化
}
if(cnt<=3)
{
ans++;
}
}
cout<<ans<<"\n";
}
return 0;
}
接下来说正解。个人认为这是最通俗易懂的解法。
可以发现暴力程序主要是在比对的时候花的时间太长了。考虑进一步优化。
作为提高组选手,看到比对字符串很容易就想到哈希。
我们尝试比对出前三个不同的地方,最后一段如果能匹配上就是一个答案,反之则不是。当然如果还没找到三处不同就已经匹配完整个
细细思考一下,容易发现哈希的匹配具有单调性,具体来讲,如果两个字符串的前
考虑二分,二分出前三个不同的地方,如果匹配完了就结束二分并累加答案,否则判断剩余部分是否匹配即可。
正确代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
unsigned long long hs[N], pw[N], ht[N], base=19991;
unsigned long long get_hash(unsigned long long hsd[], int lt, int rt)
{
return hsd[rt]-hsd[lt-1]*pw[rt-lt+1];
}
bool check(int l, int ed)
{
int st=1, r=l+ed-1;
for(int i=1;i<4;i++)
{
int lt=-1, rt=ed-st+2;
while(lt+1<rt)
{
int mid=(lt+rt)>>1;
if(get_hash(hs,l,l+mid-1)==get_hash(ht,st,st+mid-1))lt=mid;
else rt=mid;
}
l+=lt+1;
st+=lt+1;
if(st>ed)return 1;
}
return get_hash(hs,l,r)==get_hash(ht,st,ed);
}
int work()
{
string s0, s;
cin>>s0>>s;
if(s0.size()<s.size())return 0;
int len1=s0.size(),len2=s.size();
s0=" "+s0;
s=" "+s;
for(int i=1;i<=len1;i++)hs[i]=hs[i-1]*base+s0[i];
for(int i=1;i<=len2;i++)ht[i]=ht[i-1]*base+s[i];
int ans=0;
for(int i=1;i+len2-1<=len1;i++)
{
if(check(i,len2))ans++;
}
return ans;
}
signed main()
{
pw[0]=1;
for(int i=1;i<=100000;i++)pw[i]=pw[i-1]*base;
int t;
for(cin>>t;t;t--)cout<<work()<<"\n";
}