1. 程式人生 > >[TJOI2017] DNA 解題報告 (hash+二分)

[TJOI2017] DNA 解題報告 (hash+二分)

log h+ get www. signed targe 相差 ria type

題目鏈接:https://www.luogu.org/problemnew/show/P3763

題目大意:

給定原串S0,詢問S0有多少個子串和給定串S相差不到3個字母

題解:

我們枚舉S0的子串,問題轉化為如何高效的判斷兩個串是否相差不到三個字母

考慮到數據範圍,發現只能有log的時間余地

自然想到二分

solve每次找到第一個不同的位置並且返回,連續solve 4次,若S在這期間被處理完了,那麽說明兩個串相差不到3個字母

當然還有一些小細節

#include<cstdio>
#include<cstring>
#include<algorithm>
#include
<iostream> typedef unsigned long long ull; const int N=1e5+15; int lena,lenb; ull pin[N],haa[N],hab[N]; char a[N],b[N]; void H() { haa[0]=hab[0]=0; for (int i=1;i<=lena;i++) { haa[i]=haa[i-1]*113+a[i]-a; } for (int i=1;i<=lenb;i++) { hab[i]
=hab[i-1]*113+b[i]-a; } } int solve(int x,int y) { int l=1,r=lenb; while (l<r) { int mid=l+r>>1; if ((haa[x+mid-1]-haa[x-1]*pin[mid])==(hab[y+mid-1]-hab[y-1]*pin[mid])) { l=mid+1; } else r=mid; } if
(haa[x+l-1]-haa[x-1]*pin[l]!=hab[y+l-1]-hab[y-1]*pin[l]) { return l; } else return l+1; } int check(int x) { int now=1,k; for (int i=1;i<=3;i++) { k=solve(x,now); //printf("%d %d %d\n",x,now,k); x+=k;now+=k; if (now>lenb) return 1; } k=solve(x,now); x+=k-2;now+=k-2; if (now>=lenb) return 1; return 0; } int main() { pin[0]=1; for (int i=1;i<=N;i++) pin[i]=pin[i-1]*113; int T; scanf("%d",&T); while (T--) { scanf("%s",a+1); scanf("%s",b+1); lena=strlen(a+1),lenb=strlen(b+1); H(); //printf("%d\n",solve(2,3)); int re=0; for (int i=1;i<=lena-lenb+1;i++) { if (check(i)) re++; } printf("%d\n",re); } return 0; }

[TJOI2017] DNA 解題報告 (hash+二分)