CF528D Fuzzy Search (生成函数+FFT)

题目传送门

题目大意:给你两个只包含A,G,C,T的字符串$S$,$T$,$S$长$T$短,按照如下图方式匹配 解释不明白直接上图

能容错的距离不超过$K$,求能$T$被匹配上的次数

$S$串同一个位置可以被$T$的不同位置匹配多次

对4种字符分别处理,假设我们现在只讨论字符A

对于字符串AGCAATTCAT,字符A的生成函数就是1001100010

题目要求距离不超过K就能匹配,把周围距离不超过$K$的位置都变成1,形成一个新串$S‘$

$S$  1001100010

$S‘$ 1111110111

只要$T$和$S‘$的某个子串匹配时,子串中1的个数 不少于 $T$串中1的个数,就表明$T$串能被匹配上

把$T$串反转,再进行卷积,每一位都分4钟情况讨论即可

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 (1<<19)
  6 #define il inline
  7 #define dd double
  8 #define ld long double
  9 #define ll long long
 10 using namespace std;
 11
 12 int gint()
 13 {
 14     int ret=0,fh=1;char c=getchar();
 15     while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();}
 16     while(c>=‘0‘&&c<=‘9‘){ret=ret*10+c-‘0‘;c=getchar();}
 17     return ret*fh;
 18 }
 19 int idx(char c)
 20 {
 21     if(c==‘A‘) return 0;
 22     if(c==‘C‘) return 1;
 23     if(c==‘G‘) return 2;
 24     if(c==‘T‘) return 3;
 25 }
 26 const int inf=0x3f3f3f3f;
 27
 28 namespace FFT{
 29
 30 const dd pi=acos(-1);
 31 struct cp{
 32 dd x,y;
 33 friend cp operator + (const cp &s1,const cp &s2){ return (cp){s1.x+s2.x,s1.y+s2.y}; }
 34 friend cp operator - (const cp &s1,const cp &s2){ return (cp){s1.x-s2.x,s1.y-s2.y}; }
 35 friend cp operator * (const cp &s1,const cp &s2){ return (cp){s1.x*s2.x-s1.y*s2.y,s1.y*s2.x+s1.x*s2.y}; }
 36 }a[N1],b[N1],c[N1];
 37 int r[N1];
 38 void FFT(cp *s,int len,int type)
 39 {
 40     int i,j,k; cp wn,w,t;
 41     for(i=0;i<len;i++) if(i<r[i]) swap(s[i],s[r[i]]);
 42     for(k=2;k<=len;k<<=1)
 43     {
 44         wn=(cp){cos(2.0*type*pi/k),sin(2.0*type*pi/k)};
 45         for(i=0;i<len;i+=k)
 46         {
 47             w=(cp){1,0};
 48             for(j=0;j<(k>>1);j++,w=w*wn)
 49             {
 50                 t=w*s[i+j+(k>>1)];
 51                 s[i+j+(k>>1)]=s[i+j]-t;
 52                 s[i+j]=s[i+j]+t;
 53             }
 54         }
 55     }
 56 }
 57 void Main(int len,int L)
 58 {
 59     int i;
 60     for(i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
 61     FFT(a,len,1); FFT(b,len,1);
 62     for(i=0;i<len;i++) c[i]=a[i]*b[i];
 63     FFT(c,len,-1);
 64     for(i=0;i<len;i++) c[i].x/=len;
 65 }
 66 void init()
 67 {
 68     memset(a,0,sizeof(a));
 69     memset(b,0,sizeof(b));
 70 }
 71
 72 };
 73 using FFT::a; using FFT::b; using FFT::c;
 74
 75 int s[N1],t[N1],nt[N1],n,m,K,len,L;
 76 char S[N1],T[N1];
 77 void solve(int p)
 78 {
 79     FFT::init();
 80     int i,j,k,num=0;
 81     for(i=0,k=0;i<n;i++) if(s[i]==p)
 82         for(k=max(k,i-K);k<=min(n,i+K);k++) a[k].x=1;
 83     for(i=n-1,k=n-1;i;i--) if(s[i]==p)
 84         for(k=min(k,i+K);k>=max(0,i-K);k--) a[k].x=1;
 85     for(i=0;i<m;i++) if(t[i]==p) b[m-i-1].x=1,num++;
 86     FFT::Main(len,L);
 87     for(i=0;i<n;i++) if((int)(c[i].x+0.1)<num) nt[i]=1;
 88 }
 89
 90 int main()
 91 {
 92     int i,j,ans=0;
 93     scanf("%d%d%d",&n,&m,&K);
 94     scanf("%s",S); scanf("%s",T);
 95     for(i=0;i<n;i++) s[i]=idx(S[i]);
 96     for(i=0;i<m;i++) t[i]=idx(T[i]);
 97     for(len=1,L=0;len<(n+m-1);len<<=1,L++);
 98     solve(0);
 99     solve(1);
100     solve(2);
101     solve(3);
102     for(i=0;i<n;i++) if(!nt[i]) ans++;
103     printf("%d\n",ans);
104     return 0;
105
106 }  

原文地址:https://www.cnblogs.com/guapisolo/p/10353778.html

时间: 2024-11-10 08:43:17

CF528D Fuzzy Search (生成函数+FFT)的相关文章

Codeforces 528D Fuzzy Search(FFT)

题目 Source http://codeforces.com/problemset/problem/528/D Description Leonid works for a small and promising start-up that works on decoding the human genome. His duties include solving complex problems of finding certain patterns in long strings cons

[CF528D]Fuzzy Search

luogu sol 这种字符串匹配的问题显然可以把一个串\(reverse\)过来然后用\(FFT\)做吧. 对每种字母分开考虑,设两个多项式\(A(x),B(x)\),其中 \[A(x)=\sum_{i=0}^{n-1}[区间[i-k,i+k]内存在该种字符]x^i\] \[B(x)=\sum_{i=0}^{n-1}[t[i]为该种字符]x^i\] 然后两个多项式卷一下就是这种字符在第\(i\)个位置上的匹配吧. 最后对每次的系数求和,若恰好等于\(|T|\)则说明匹配成功. 复杂度\(O(4

B - Fuzzy Search (FFT)

题目链接:https://cn.vjudge.net/contest/281959#problem/B 题目大意:给你n,m,k.然后输入两个字符串,n代表第一个字符串s1,m代表第二个字符串s2,然后问你第二个字符串在第一个字符串能匹配的次数(选定第一个字符串的位置之后,任意s2中一个字符串,都能在s1对应的位置左右k个都能找到相同的字符). 具体思路:和 这一篇的思路基本使用一样的. AC代码: 1 #include<iostream> 2 #include<cstring>

【BZOJ3771】Triple 生成函数+FFT

[BZOJ3771]Triple Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!” 水神把斧头扔在一边,又拿起一个东西问: “这把斧头,是不是你的?” 樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!” 水神又把手上的东西扔在一边,拿起第三个东西问: “这把斧头,是不是你的?” 樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了. 于是他又一次答:“

HDU 5307 He is Flying (生成函数+FFT)

题目传送门 给你一个长度为$n$的自然数序列$a$,定义一段区间的权值为这一段区间里所有数的和,分别输出权值为$[0,\sum a_{i}]$的区间的长度之和 想到了生成函数的话,这道题并不难做.但很多细节真是不太好搞 我们首先预处理出前缀和s,那么一段区间$[l,r]$的权值就是$s_{r}-s_{l-1}$ 容易联想到卷积 第一个多项式是 区间右端点的前缀和 作为指数的生成函数,每一项的系数是 右端点的编号之和 第二个多项式是 区间左端点的前缀和 作为指数的生成函数,每一项的系数是 左端点的

UVA 12633 Super Rooks on Chessboard (生成函数+FFT)

题面传送门 题目大意:给你一张网格,上面有很多骑士,每个骑士能横着竖着斜着攻击一条直线上的格子,求没被攻击的格子的数量总和 好神奇的卷积 假设骑士不能斜着攻击 那么答案就是没被攻击的 行数*列数 接下来考虑斜着攻击对答案的贡献 以左下角为坐标原点建立坐标系,发现一条对角线的点的$(x+y)$坐标是相同的 考虑卷积,设计两个生成函数$a,b$ 如果第i行没骑士,则$a_{i}=1$,反之为$0$ 如果第i列没骑士,则$b_{i}=1$,反之为$0$ 我们对两个式子进行卷积,可以求出每一条对角线上还

【JSOI2012】 分零食 生成函数 FFT

我们构造$f(x)$的生成函数$G(x)$,那么显然$[x^k]G(x)=Ok^2+Sk+U$ 那么显然,答案即为$\sum_{i=1}^{n} [x^m]G^i(x)$ 我们构造答案的生成函数$F(x)=\sum_{i=1}^{n} G^i(x)$ 根据等比数列求和公式,$F(x)=\dfrac{1-G(x)}{1-G^{A+1}(x)}$ 如果去等比数列求和的话,你需要多项式快速幂+多项式求逆,时间复杂度显然是$O(m\ log\ m)$的. 然而这个模数并不是质数,所以这么搞不是很好搞.

Fuzzy Search

题意: 考虑模板串B和给定串A,给定K,对于模板串上给定位置j的字符,如果能在给定串上i左右K个字符内找到相同字符,则说可以匹配. 问有多少匹配. 解法: 考虑对于每一种字符分开求. 对于当前字符ch,将B串中为此字符的位置标为1其他位置为0,将A串中所有可以匹配ch的位置标为1,其他为0,这样 记$c_i$表示以 i 为起点字符ch可以匹配到几个. $$c_i = \sum_{ 0 \leq j<m} { b_j a_{i+j} }$$ $$c_i = \sum_{0 \leq k \leq

FFT的应用

FFT的应用 概述 FFT的模板很简单,大家都会背,于是出题的空间就在于建模了.FFT的题目难在建模,往往需要将问题抽象出来,经过一系列转化后得到乘积式的和,再赋予式子各个项的系数一定的意义即可. 基本形式 对于类似\(\sum_{i+j=N+k}a_ib_j\)的式子,可以直接通过FFT计算. 其中N是定值,表示元素个数:k是变量,是题目中的系数,a和b是间接已知数组,当a与b的系数和为定值时,可将一个翻转,否则直接计算. 例题:P3723?[AH2017/HNOI2017]礼物 直接计算卷积