Codeforces528 D. Fuzzy Search(bitest)

tech2022-08-12  150

题意:

给定长度为n的串S和长度为m的串T,还有一个整数k 串只由ACGT组成,问T串在S串中出现了多少次,匹配机制比较特殊: 定义T[i]能匹配上S[j],当且仅当T[i]在S[j-k,j+k]中出现过,即存在偏移位差k

数据范围:n,m,k<=2e5

解法:

考虑没有偏移的时候怎么计算匹配数, 可以KMP,但是偏移之后就不行了, 考虑用bitset计算匹配: 对每个字符集单独考虑, 假设当前选择字符为x, 令S串中x字符为1,其他字符为0,那么变成一个01,4种字符处理就会得到401,A的01串设为bitset(A). 开一个bitset<N>ans,赋值为全1, 遍历T串,当遇到t[i]的时候,ans&=(bitset(t[i])>>(i-1)) 剩下来的1表示t[i]可以被匹配的开头位置, 遍历完之后,还剩下的1就是合法的开头位置了. 每个字符可以被匹配的范围为[i-k,i+k], 这个可以差分预处理出来,然后也得到4bitset() 然后按照上面的匹配做就行了.

code:

#include<bits/stdc++.h> using namespace std; const int maxm=2e5+5; char s[maxm]; char t[maxm]; int d[4][maxm]; int n,m,k; bitset<maxm>bit[4],temp; signed main(){ map<char,int>mp; mp['A']=0; mp['C']=1; mp['G']=2; mp['T']=3; // scanf("%d%d%d",&n,&m,&k); scanf("%s",s+1); scanf("%s",t+1); //转化为数字,方便处理 for(int i=1;i<=n;i++){ s[i]=mp[s[i]]; } for(int i=1;i<=m;i++){ t[i]=mp[t[i]]; } //差分预处理 for(int i=1;i<=n;i++){ d[s[i]][max(1,i-k)]++; d[s[i]][min(n,i+k)+1]--; } for(int i=0;i<4;i++){ for(int j=1;j<=n;j++){ d[i][j]+=d[i][j-1]; if(d[i][j]){ bit[i][j]=1; } } } // for(int i=1;i<=n;i++){ temp[i]=1; } for(int i=1;i<=m;i++){//最后为1的位置就是合法位置. temp&=(bit[t[i]]>>(i-1)); } int ans=0; for(int i=1;i<=n;i++){ ans+=temp[i]; } cout<<ans<<endl; return 0; }
最新回复(0)