原题题面

加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列 SSS,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列 SSS,任意修改其中不超过 3 个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在 DNA 链 S0S_0S0​上的位置。所以你需要统计在一个表现出吃藕性状的人的 DNA 序列 S0S_0S0​上,有多少个连续子串可能是该基因,即有多少个S0S_0S0​的连续子串修改小于等于三个字母能够变成 SSS。

输入格式

第一行有一个整数TTT,表示有几组数据。
每组数据第一行一个长度不超过 10510^5105的碱基序列S0S_0S0​。
每组数据第二行一个长度不超过10510^5105的吃藕基因序列 SSS。

输出格式

共TTT行,第iii行表示第iii组数据中,在S0S_0S0​中有多少个与SSS等长的连续子串可能是表现吃藕性状的碱基序列。

输入样例

1
ATCGCCCTA
CTTCA

输出样例

2

题面分析

这本是一道后缀自动机的题目,但也有题解用了FFT,本篇博客采用了FFT的方法。
我们记第一个串为s1s1s1,第二个串为s2s2s2。
对于字符集{A,C,G,T}\{A,C,G,T\}{A,C,G,T},我们对于每个字符依次处理,并记匹配到了该字符时为1,未匹配到该字符时为0,得到两个数组A,BA,BA,B。
那么对于s1s1s1串中的[k,k+len(s2)][k,k+len(s2)][k,k+len(s2)]和s2s2s2的[0,len(s2)−1][0,len(s2)-1][0,len(s2)−1]可以成功匹配的位数为
∑i=0len(s2)−1A[k+i]B[i]\sum_{i=0}^{len(s2)-1}{A[k+i]B[i]}i=0∑len(s2)−1​A[k+i]B[i]
这个格式长得就很像卷积,我们设C[i]=B[len(s2)−i−1]C[i]=B[len(s2)-i-1]C[i]=B[len(s2)−i−1],得到原式等价于
∑i=0len(s2)−1A[k+i]C[len(s2)−i−1]\sum_{i=0}^{len(s2)-1}{A[k+i]C[len(s2)-i-1]}i=0∑len(s2)−1​A[k+i]C[len(s2)−i−1]

∑i+j=len(s2)+k−1A[i]C[j]\sum_{i+j=len(s2)+k-1}{A[i]C[j]}i+j=len(s2)+k−1∑​A[i]C[j]
用FFT算出四个字符的结果后相加,再统计[len(s2)−1,len(s1)][len(s2)-1,len(s1)][len(s2)−1,len(s1)]的位置的结果就是符合题意的串个数即可。
假设我们记FFt的结果中某个符合条件的为ans[i]ans[i]ans[i],那么ans[i]+3≥len(s2)ans[i]+3\geq len(s2)ans[i]+3≥len(s2)。

AC代码(900ms)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define cp complex<double>
const int maxn=4e5;
cp a[maxn+10];
cp b[maxn+10];
char s1[maxn+10];
char s2[maxn+10];
ll ans[maxn+10];
char charset[]={'A', 'C', 'G', 'T'};
namespace FFT
{const double pi=acos(-1.0);ll rev[maxn+10];int getBit(int k){int bit=0;while((1<<bit)<k)bit++;return bit;}void solve(cp *a, int n, int inv)//inv是1时是系数转点值,-1是点值转系数{int bit=getBit(n);for(int i=0; i<n; ++i){rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));if (i<rev[i]) swap(a[i], a[rev[i]]);}for(int mid=1; mid<n; mid*=2){cp w(cos(pi*1.0/mid), inv*sin(pi*1.0/mid));//单位根for(int i=0; i<n; i+=mid*2){cp omega(1, 0);for(int j=0; j<mid; j++, omega*=w){cp x=a[i+j];cp y=omega*a[i+j+mid];a[i+j]=x+y;a[i+j+mid]=x-y;//蝴蝶变换}}}if (inv==-1){for(int i=0; i<n; i++){a[i].real(a[i].real()/n);}}}
}
void solve()
{int t;scanf("%d", &t);while(t--){scanf("%s%s", s1, s2);int len1=strlen(s1);int len2=strlen(s2);int len=1<<FFT::getBit(len1+len2);for(int i=0; i<len; ++i)ans[i]=0;for(int z=0; z<4; ++z){for(int i=0; i<len1; ++i){a[i].real(s1[i]==charset[z] ? 1 : 0);a[i].imag(0);}for(int i=len1;i<len;++i){a[i]=cp(0,0);}for(int i=0; i<len2; ++i){b[len2-i-1]=(s2[i]==charset[z] ? 1 : 0);b[i].imag(0);}for(int i=len2;i<len;++i){b[i]=cp(0,0);}FFT::solve(a, len, 1);FFT::solve(b, len, 1);for(int i=0; i<len; ++i){a[i]*=b[i];}FFT::solve(a, len, -1);for(int i=0; i<len; ++i){ans[i]+=(ll) (a[i].real()+0.5);
//                printf("%lld ", ans[i]);}
//            printf("\n");}ll cnt=0;for(int i=len2-1; i<len1; ++i){if (ans[i]+3>=len2)cnt++;}printf("%lld\n", cnt);}
}
signed main()
{//    ios_base::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
#ifdef ACM_LOCALfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);long long test_index_for_debug=1;char acm_local_for_debug;while(cin>>acm_local_for_debug){cin.putback(acm_local_for_debug);if (test_index_for_debug>100){throw runtime_error("Check the stdin!!!");}auto start_clock_for_debug=clock();solve();auto end_clock_for_debug=clock();cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;cerr<<"Test "<<test_index_for_debug++<<" Run Time: "<<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;cout<<"--------------------------------------------------"<<endl;}
#elsesolve();
#endifreturn 0;
}

后记

FFT居然可以处理部分字符串问题,绝了…
DrGilbert 2020.10.5

P3763 [TJOI2017]DNA (FFT)相关推荐

  1. 洛谷P3763 [Tjoi2017]DNA 【后缀数组】

    题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...

  2. P3763 [TJOI2017]DNA(SAM+dfs)

    LINK SAM写法 记得以前是用 F F T FFT FFT写的,推狮子翻来覆去- 然而这不是被 S A M SAM SAM秒掉的垃圾题吗??!! 建立 S A M SAM SAM,直接从根节点去 ...

  3. BZOJ4892: [Tjoi2017]dna

    BZOJ4892: [Tjoi2017]dna Description 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S, 有这个序列的碱基序列就会表现出喜欢吃藕的性状. 但是研究人员发现 ...

  4. [TJOI2017]DNA --- 后缀数组

    [TJOI2017]DNA 题目描述 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S, 有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个 ...

  5. [TJOI2017]DNA

    Description: 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够 ...

  6. BZOJ 4892: [Tjoi2017]DNA(SA+RMQ / SAM)

    Description 加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的 性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够 ...

  7. 浅谈 FFT (终于懂一点了~~)

    FFT(离散傅氏变换的快速算法) FFT(Fast Fourier Transformation)是离散傅氏变换(DFT)的快速算法.即为快速傅氏变换.它是根据离散傅氏变换的奇.偶.虚.实等特性,对离 ...

  8. 2018十二月刷题列表

    Preface \(2018\)年的尾巴,不禁感慨自己这一年的蜕变只能用蜕变来形容了. 而且老叶说我们今年没的参加清北冬令营可以参加CCF在广州二中举办的冬令营,只要联赛\(390+\)就应该可以报. ...

  9. 如何选择优化算法遗传算法_用遗传算法优化垃圾收集策略

    如何选择优化算法遗传算法 Genetic Algorithms are a family of optimisation techniques that loosely resemble evolut ...

最新文章

  1. usaco Cow Pedigrees
  2. linux安全问答(1)
  3. 《工业大数据白皮书》2019版正式发布
  4. mysql的如何输入dateadd_mysql中date_add()函数的使用?
  5. 中国量化投资将呈现三大发展趋势
  6. Semaphore源码分析
  7. 2020年度智能音箱主控方案汇总,涵盖15大芯片品牌推出的34款解决方案
  8. Servlet上传文件和下载文件示例
  9. Netty工作笔记0026---NIO 网络编程应用--群聊系统1---编写服务器1
  10. spring boot之http,页面状态跳转与异常处理实战
  11. 剑指offer面试题12. 矩阵中的路径(矩阵搜索)(深度优先搜索)(剪枝)
  12. c语言错误spawning,C语言一直出现Error spawning cl.exe的解决办法
  13. Linux入门:PuTTY实现Linux和Windows文件互传
  14. [数字图像处理·冈萨雷斯 ] 图像文件格式
  15. 上海交通大学计算机专业考研多少分进复试,2019考研:初试分数370+,有希望进上海交通大学么?...
  16. HPD健康产品申明认证
  17. slave-pending-jobs-size-max导致主从延迟
  18. 十二核能让联发科引爆核弹战吗?
  19. java教程 电子工业出版社_Java程序设计实用教程
  20. 运行python程序电脑卡死了怎么办_【贴士】电脑运行卡或软件卡死无响应怎么办?...

热门文章

  1. No boot filename received
  2. “高精尖”智慧钢厂轻松打造!图扑软件数字孪生yyds
  3. 【博学谷学习记录】超强总结,用心分享|字体图标介绍
  4. python语句的执行结果是_以下是 print( \nPython)语句运行结果的是().
  5. 微信小程序云数据库实现注册
  6. 2019年,SEO关键词KPI考核指标有哪些? 1
  7. mock模拟接口测试 vue_VUE使用Mock模拟接口
  8. Java基础知识 廖雪峰教程笔记
  9. Maven使用之packing篇
  10. GD32上FAL Flash分区驱动移植及Easyflash与FlashDB移植说明