列表

详情


NC231445. Fuzzy Search

描述

给出一个门限值 k 和两个只包含 四种字符的基因串 ST。现在你要找出在下列规则中 TS 中出现了几次。

TS 的第 i 个位置中出现,当且仅当把 T 的首字符和 S 的第 i 个字符对齐后,T 中的每一个字符能够在 S 中找到一个位置偏差不超过 k 的相同字符。

即对于所有的 ,都存在一个 使得

例如 时, 出现在 2 号, 3 号和 6 号位置。 (编号从 1 开始。)

输入描述

第一行有三个整数 n , m , k ,表示 S 的长度, T 的长度和"门限值"。 

第二行给出基因串S,第三行给出基因串T,且两个串都只包含大写字母

输出描述

输出一个整数,表示 TS 中出现的次数。

示例1

输入:

10 4 1
AGCAATTCAT
ACAT

输出:

3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 2084ms, 内存消耗: 51784K, 提交时间: 2022-10-19 16:50:48

#include <bits/stdc++.h>
#define IOS   ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define xs(a) cout<<setiosflags(ios::fixed)<<setprecision(a);
#define FOR(i, a, b) for (ll (i) = (a); (i) <= (b); (i)++)
#define ROF(i, a, b) for (ll (i) = (a); (i) >= (b); (i)--)
using namespace std;
#define ull unsigned long long
#define ll long long
typedef pair<ll,ll> pll;
const int N=2e6+5;
const int mod=1e9+7;
/*-----------------------------------------------------------------------------------------------*/
typedef complex<double> com;
const double pi = acos(-1.0);
ll rev[N];
//  fft部分
inline void fft(com *a,int len,int type){
	for(int i=0;i<len;i++){
		if(i<rev[i])	swap(a[i],a[rev[i]]);
	}
	for(int mid=1;mid<len;mid<<=1){
		com W(cos(pi/mid),type*sin(pi/mid));
		for(int j=0;j<len;j+=mid<<1){
			com w(1,0);
			for(int k=0;k<mid;k++){
				com x=a[j+k],y=w*a[j+mid+k];
				a[j+k]=x+y;
				a[j+mid+k]=x-y;
				w=w*W;
			}
		}
	}
}
com a[N],b[N];
ll d[N],cnt[N];
string s,t;
ll n,m,k;
ll M=1;
void cal(char c){
    FOR(i,0,M)a[i]=b[i]=com(0,0),d[i]=0;
    ll sz=s.size();
    for(ll i=0;i<sz;i++){
        if(s[i]==c){
            ROF(j,min(i+k,sz),max(i-k,0ll)){
                if(d[j])break;
                d[j]=1;
            }
        }
    }
    for(int i=0;i<sz;i++){
        if(d[i])a[i]=com(1,0);
    }
    ll tz=t.size();
    for(int i=0;i<m;i++){
        if(t[i]==c)b[m-i-1]=com(1,0);
    }
    fft(a,M,1);fft(b,M,1);
    for(int i=0;i<M;i++)a[i]=a[i]*b[i];
    fft(a,M,-1);
    for(int i=0;i<n;i++)cnt[i]+=int(a[i].real()/M+0.5);
}

signed main(){
    cin>>n>>m>>k;
    cin>>s>>t;
    ll l=0;
    while(M<=(n+m)*2)	M<<=1,l++;
    for(int i=0;i<M;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
    cal('A');cal('G');cal('C');cal('T');
    ll ans=0;
    for(int i=0;i<n;i++) if(cnt[i]==m)ans++;
    cout<<ans<<endl;



    return 0;
}

C++ 解法, 执行用时: 962ms, 内存消耗: 4288K, 提交时间: 2022-02-24 21:30:19

#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int mp[200],a[N][4];
bitset<N> bs[4],ans;
int main()
{
	ios::sync_with_stdio(false);
	int n,m,k;
	string s,t;
	cin>>n>>m>>k>>s>>t;
	mp['A']=0,mp['C']=1,mp['G']=2,mp['T']=3;
	for(int i=0;i<n;i++)
	{
		a[max(0,i-k)][mp[s[i]]]++;
		a[min(n,i+k+1)][mp[s[i]]]--;
	}
	for(int i=0;i<n;i++)
	{
		ans[i]=1;
		for(int j=0;j<4;j++)
		{
			if(i)
				a[i][j]+=a[i-1][j];
			if(a[i][j])	
				bs[j][i]=1;
			else
				bs[j][i]=0;
		}
	}
	for(int i=0;i<m;i++)
		ans&=(bs[mp[t[i]]]>>i);
	int sum=0;
	for(int i=0;i<n;i++)
		sum+=(ans[i]==1);
	printf("%d\n",sum);
	return 0;
}

上一题