FFT与一些冷门问题
FFT也能用于一些特殊的字符串匹配与最小化问题。
Prob 1 : 给出模式串A与文本串B,两个串中只有26个大写字母与通配符'?'(即可以任意匹配一个字符),求A在B中的匹配数。要求以FFT为例给出上限为O(nlogn)的算法。
Prob 2 : 给出模式串A与文本串B,字符集很小,求A在B中的匹配数,允许有k个字符不同。要求以FFT为例给出上限为O(nlogn*|S|)的算法。
Prob 3 : 给出数列a和b,长度均为n,a可以顺时针转动但不能翻转,最小化sigma(ai*bi)。要求以FFT为例给出上限为O(nlogn)的算法。
不知道是什么东西的引导
我们先看看FFT干了什么,就是个卷积。
以数组a和b为例(这里下标从1开始),a有4位,b有8位,卷出的结果放在c数组中。
然而并没有什么用处。我们再往后看几位:
虽然FFT时会把a数组给自动补全,但从实际意义上来讲,只是整个a数组与b数组中四个数相乘放进c中。
不难发现,此时的下标就是一个“占位符”。
我们顺便把a数组反一反,就有:
这样就有很好的性质了,c数组中从第5位开始,每往后一位就是整个a数组与b数组中连续的四位积的和。
同样可以拓展到更大的数组中,接下来的题目就要利用这个特点。
Prob 1
我们发现字符串的匹配很类似于上述图片中一位位算过去。
先不考虑通配符,只是普通的字符串匹配。定义为A的第x位与B的第y位的匹配度。若C为0,则是匹配的。
再定义,表示B字符串中以x为结尾,向前m-1位与A字符串的匹配度。我们天真地考虑若P为0,则是匹配的。
但是C有正有负,因此一旦连续的几位的可重集是相同的,P的结果就为0。
所以在C上动手脚。干脆加个平方吧:
这样,
但还不能优化!因此我们又看了看上面的图,把A字符串反了过来。定义
则
注意到(m-i-1)+(x-m+1+i)==x,有:
这样S与B做一遍卷积就行了。S与B的值取字符串的字符值就行了。
那带上通配符,只要有任何字符遇上“?”,C的值就必须是0。这样在原来P的式子中,后面乘上S与B中相应的第几位,若是“?”,给其赋值为0。则
做三次FFT,加起来等于0的,即为匹配。
//源:https://www.luogu.org/problemnew/show/P4173
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
const double pi=3.1415926535898;
struct com
{
double a,b;
com(double A=,double B=){a=A,b=B;}
void operator=(com x){a=x.a,b=x.b;}
com operator+(com x){return com(a+x.a,b+x.b);}
com operator-(com x){return com(a-x.a,b-x.b);}
com operator*(com x){return com(a*x.a-b*x.b,a*x.b+b*x.a);}
com operator/(double d){return com(a/d,b/d);}
com operator*(double d){return com(a*d,b*d);}
}A[maxn],B[maxn],ans[maxn];
int n,m,limit,r[maxn],len,g1[maxn],g2[maxn];
char ch;
int re(int x)
{
int sum=;
for(int i=;i<len;++i)
{
sum=sum*+x%;
x/=;
}
return sum;
}
void FFT(com*A,int g)
{
for(int i=;i<limit;++i)
if(i<r[i])swap(A[i],A[r[i]]);
for(int i=;i<=limit;i*=)
{
com w(cos(*pi/i),g*sin(*pi/i));
for(int j=;j<limit/i;++j)
{
com d(,);
for(int k=;k<i/;++k)
{
com a=A[i*j+k],b=d*A[i*j+i/+k];
A[i*j+k]=a+b;
A[i*j+i/+k]=a-b;
d=w*d;
}
}
}
}
void out(com*A)
{
for(int i=;i<limit;++i)cout<<A[i].a<<' ';
cout<<endl;
}
void get(com*A,com*B)
{
FFT(A,);
FFT(B,);
for(int i=;i<limit;++i)A[i]=A[i]*B[i];
FFT(A,-);
for(int i=;i<limit;++i)A[i]=A[i]/limit;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=n-;i>=;--i)
{
cin>>ch;
if(ch!='*')
{
int x=ch-'a'+;
A[i]=g1[i]=x;
}
}
for(int i=;i<m;++i)
{
cin>>ch;
if(ch!='*')
{
int x=ch-'a'+;
g2[i]=x;
B[i]=x*x*x;
}
}
limit=;
while(limit<n+m+)limit*=,++len;
for(int i=;i<limit;++i)r[i]=re(i);
get(A,B);
for(int i=;i<limit;++i)ans[i]=A[i]; for(int i=limit-;i>=;--i)A[i]=g1[i]*g1[i]*g1[i];
for(int i=;i<limit;++i)B[i]=g2[i];
get(A,B);
for(int i=;i<limit;++i)ans[i]=ans[i]+A[i]; for(int i=limit-;i>=;--i)A[i]=g1[i]*g1[i];
for(int i=;i<limit;++i)B[i]=g2[i]*g2[i];
get(A,B);
for(int i=;i<limit;++i)ans[i]=ans[i]-A[i]*; int tot=;
for(int i=n-;i<m;++i)if(int(ans[i].a+0.5)==)++tot;
cout<<tot<<endl;
for(int i=n-;i<m;++i)if(int(ans[i].a+0.5)==)cout<<i-n+<<' ';
cout<<endl;
return ;
}
代码
Prob 2
若字符只有’0'和'1'的呢?按照上面的做法,最后结果小于等于2的即为匹配(因为会有地方算两遍)。
再拓展一下,字符集多大就做几遍。最后的和加起来即可。
但由于一些奇妙的原因,至今我交不过去。只有网址。
其实随便哈希就能过了,SA也行。
https://www.luogu.org/problemnew/show/P3763
Prob 3
仍然是老套路。我们只要把其中某个数组的长度变为两倍,再重复写下前面的数就行了。
类似的题目:https://www.luogu.org/problemnew/show/P3723
最后,如果能用一些数据结构或方法来维护的话就别写FFT了。
FFT与一些冷门问题的更多相关文章
- 并行计算提升32K*32K点(32位浮点数) FFT计算速度(4核八线程E3处理器)
对32K*32K的随机数矩阵进行FFT变换,数的格式是32位浮点数.将产生的数据存放在堆上,对每一行数据进行N=32K的FFT,记录32K次fft的时间. 比较串行for循环和并行for循环的运行时间 ...
- 【BZOJ-2179&2194】FFT快速傅里叶&快速傅里叶之二 FFT
2179: FFT快速傅立叶 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2978 Solved: 1523[Submit][Status][Di ...
- 为什么FFT时域补0后,经FFT变换就是频域进行内插?
应该这样来理解这个问题: 补0后的DFT(FFT是DFT的快速算法),实际上公式并没变,变化的只是频域项(如:补0前FFT计算得到的是m*2*pi/M处的频域值, 而补0后得到的是n*2*pi/N处的 ...
- FFT NNT
算算劳资已经多久没学新算法了,又要重新开始学辣.直接扔板子,跑...话说FFT算法导论里讲的真不错,去看下就懂了. //FFT#include <cstdio> #include < ...
- CC countari & 分块+FFT
题意: 求一个序列中顺序的长度为3的等差数列. SOL: 对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人... 考虑分块以后的序列: ...
- ECF R9(632E) & FFT
Description: 上一篇blog. Solution: 同样我们可以用fft来做...就像上次写的那道3-idoit一样,对a做k次卷积就好了. 同样有许多需要注意的地方:我们只是判断可行性, ...
- fft练习
数学相关一直都好弱啊>_< 窝这个月要补一补数学啦, 先从基础的fft补起吧! 现在做了 道. 窝的fft 模板 (bzoj 2179) #include <iostream> ...
- FFT时域与频域的关系,以及采样速率与采样点的影响
首先对于FFT来说,输入的信号是一个按一定采样频率获得的信号序列,而输出是每个采样点对应的频率的幅度(能量). 下面详细分析: 在FFT的输出数据中,第一个值是直流分量的振幅(这样对应周期有无穷的可能 ...
- 【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT
前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT.在网上找了很多这方面的资料做实验并进行 ...
随机推荐
- Java作业(一)
再此次的Java考试中发现自己的不足,无法套用HTML模板进行编程,说实话拿到的第一刻自己有些懵,不知道怎么去操作, 后来通过查询操作了一些,但是整个人还是懵懵的,不知道下一步怎么办,怎么去连接后台和 ...
- Interesting (manacher + 前缀和处理)
题意:相邻的两端回文串的价值为两个回文串总的区间左端点 × 区间右端点.然后计算目标串中所有该情况的总和. 思路:首先用manacher求出所有中心点的最大半径,然后我们知道对于左区间我们把贡献记录在 ...
- Lucky 7 (容斥原理 + 中国剩余定理)
题意:求满足7的倍数,不满足其他条件num % p == a 的num的个数. 思路:利用中国剩余定理我i们可以求出7的倍数,但是多算了不满足约定条件又得减去一个,但是又发现多减了,又得加回来.如此, ...
- restful规范快速记忆
restful规范: 十个规则: 用户发来请求,url必须: 1.因为是面向资源编程,所以每个URL代表一种资源,URL中尽量不要用动词,要用名词 2.尽量使用HTTPS,https代替http 3. ...
- centos7.3配置python2、3环境与配置各自pip
环境:CentOS-7-x86_64-Everything-1611 No.1 查看CentOS对Python的默认依赖 [root@cs ~]# ls /usr/bin/python* /usr/b ...
- eclipse软件仿真操作
1.编写程序代码(以SDRAM为例) 1.1 编写head.s汇编文件 .equ SDRAM_BASE, 0x30000000 .equ MEM_CTL_BASE, 0x48000000 .text ...
- CVE-2018-8120 Windows权限提升
来源 : bigric3/cve-2018-8120 Detail : cve-2018-8120-analysis-and-exploit 演示图 下载 CVE-2018-8120.zip
- HAOI(多省联考)2019退役记
等着回头写 算了今天先写点 Day -1 打扫下机房,不想写题,不想考试.... Day 0 上午颓了一上午 下午看下考场结果去早了 ZYZ 全员进队! Day 1 上来T1,01Tire!,开码,半 ...
- 剧透 & 报名 | 蚂蚁金服ATEC城市峰会·上海即将开幕
小蚂蚁说: 2019年1月4日,蚂蚁金服ATEC城市峰会将以“数字金融新原力(The New Force of Digital Finance)”为主题,在中国上海举办.蚂蚁金服ATEC(Ant Te ...
- 查漏补缺之——Java多线程
复习面试题中遇到锁的内容当时大一学习的时候感觉懵懂,现在重新复习一下. 1.1多线程 1.1.1线程 1.什么是线程 线程是程序执行的一条路径,一个进程中包含多条进程 2.并行与并发 并行是两个任务同 ...