卷积FFT、NTT、FWT
先简短几句话说说FFT....
多项式可用系数和点值表示,n个点可确定一个次数小于n的多项式。
多项式乘积为 f(x)*g(x),显然若已知f(x), g(x)的点值,O(n)可求得多项式乘积的点值。
我们所需要的就是O(nlogn)快速地将两个系数多项式表示成点值多项式,O(n)求得乘积的点值表示后O(nlogn)还原成系数多项式。
这里就需要套FFT板子了...
FFT中取n个单位根,需要n是2的幂。
又因为n个点可确定一个次数小于n的多项式,所以n > 乘积多项式的最高次数。
以上。
HDU4609 n个木棍任取三根能组成三角形的概率。
数组开小莫名T,WA.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 4e5+;
struct comp{
double r,i;comp(double _r=,double _i=){r=_r;i=_i;}
comp operator+(const comp x){return comp(r+x.r,i+x.i);}
comp operator-(const comp x){return comp(r-x.r,i-x.i);}
comp operator*(const comp x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}
};
const double pi=acos(-1.0);
void FFT(comp a[],int n,int t){
for(int i=,j=;i<n-;i++){
for(int s=n;j^=s>>=,~j&s;);
if(i<j)swap(a[i],a[j]);
}
for(int d=;(<<d)<n;d++){
int m=<<d,m2=m<<;
double o=pi/m*t;comp _w(cos(o),sin(o));
for(int i=;i<n;i+=m2){
comp w(,);
for(int j=;j<m;j++){
comp &A=a[i+j+m],&B=a[i+j],t=w*A;
A=B-t;B=B+t;w=w*_w;
}
}
}
if(t==-)for(int i=;i<n;i++)a[i].r/=n;
}
comp x[N];
ll num[N], sum[N];
int main(){
int T; scanf("%d", &T);
while(T--){
memset(num, , sizeof num);
int n, u, maxnum = -; scanf("%d", &n);
for(int i = ; i < n; i++){
scanf("%d", &u);
maxnum = max(maxnum, u), num[u]++;
}
int len = ;
while(len <= maxnum*) len <<= ;
for(int i = ; i < len; i++)
x[i] = comp(num[i], );
FFT(x, len, );
for(int i = ; i < len; i++)
x[i] = x[i]*x[i];
FFT(x, len , -);
for(int i = ; i < len; i++)
sum[i] = x[i].r+0.5;
for(int i = ; i < len; i+=)
sum[i] -= num[i>>];//去掉两次取的木棍相同的
for(int i = ; i < len; i ++)
sum[i] >>= ;//算了2次
for(int i = ; i < len; i++)
sum[i] += sum[i-];
ll tot = (ll)n*(n-)*(n-)/, ans = tot;
for(int i = ; i <= maxnum; i++)
ans -= num[i]*sum[i];//去掉不能组成三角形的
printf("%.7f\n", 1.0*ans/tot);
}
return ;
}
LA4671 给出A串与B串,只含小写字母a、b。问:A串中有多少本质不同的子串满足 与B串长度相同 且 与B串相对应位置字符不同的数量小于k。
题解:a做1,b做0。将B倒着来一遍和A做卷积,可得有多少位置A串与B串都是a。a做0,b做1再来一遍即可。
hash!37做基1000173169做模会冲突!1e9+7做基1e9+9做模也会冲突!双哈希可以过,37做基2^64做模可过,37做基100000000173169LL做模也可过....
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N = 4e5+;
struct comp{
double r,i;comp(double _r=,double _i=){r=_r;i=_i;}
comp operator+(const comp x){return comp(r+x.r,i+x.i);}
comp operator-(const comp x){return comp(r-x.r,i-x.i);}
comp operator*(const comp x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}
};
const double pi=acos(-1.0);
void FFT(comp a[],int n,int t){
for(int i=,j=;i<n-;i++){
for(int s=n;j^=s>>=,~j&s;);
if(i<j)swap(a[i],a[j]);
}
for(int d=;(<<d)<n;d++){
int m=<<d,m2=m<<;
double o=pi/m*t;comp _w(cos(o),sin(o));
for(int i=;i<n;i+=m2){
comp w(,);
for(int j=;j<m;j++){
comp &A=a[i+j+m],&B=a[i+j],t=w*A;
A=B-t;B=B+t;w=w*_w;
}
}
}
if(t==-)for(int i=;i<n;i++)a[i].r/=n;
}
comp x[N], y[N];
char a[], b[];
int ans[N];
//hash
ull xp[] = {}, H[];
void initHash(){
H[] = a[];
for(int i = ; a[i]; i++)
H[i] = H[i-]*31uLL+a[i];
}
ull askHash(int l, int r){
if(l == ) return H[r];
return H[r]-H[l-]*xp[r-l+];
} int main(){
for(int i = ; i < ; i++) xp[i] = xp[i-]*31uLL; int ca = , K;
while(scanf("%d", &K), K != -){
scanf(" %s %s", a, b);
int lenA = strlen(a), lenB = strlen(b), len = ;
if(lenA < lenB){
printf("Case %d: %d\n", ca++, );
continue ;
} for(int i = ; i < lenB--i; i++)
swap(b[i], b[lenB--i]);
while(len <= lenA+lenB) len <<= ; for(int i = ; i < len; i++){
x[i] = comp(i < lenA? (a[i] == 'a'): , );
y[i] = comp(i < lenB? (b[i] == 'a'): , );
}
FFT(x, len, );
FFT(y, len, );
for(int i = ; i < len; i++)
x[i] = x[i]*y[i];
FFT(x, len, -);
for(int i = ; i < len; i++)
ans[i] = x[i].r+0.5; for(int i = ; i < len; i++){
x[i] = comp(i < lenA? (a[i] == 'b') : , );
y[i] = comp(i < lenB? (b[i] == 'b') : , );
}
FFT(x, len, );
FFT(y, len, );
for(int i = ; i < len; i++)
x[i] = x[i]*y[i];
FFT(x, len, -);
for(int i = ; i < len; i++)
ans[i] += x[i].r+0.5; initHash();
set<ull> se;
for(int i = lenB-; i < lenA; i++)
if(ans[i] >= lenB-K)
se.insert(askHash(i-lenB+, i));
printf("Case %d: %d\n", ca++, (int)se.size());
}
return ;
}
=================================分割线===================================
NTT
NTT与FFT类似,FFT用复数形式会有精度损失,而NTT则是在整数域内取模意义下,无精度损失。
如果 P = r⋅2k +1 是个素数,G是模P下的一个原根,那么在mod P 意义下,可以处理 2k 以内规模的数据 。
G在模P下的阶为 P-1,即 r⋅2k
那么Gr 在模P下的阶为2k ,这里的 Gr 即等价于FFT里的wn .
那么我们用模P下的卷积运算就不会产生精度损失。
P = 998244353 = 119*223+1, 能够处理223 = 8e6+ 规模的数据,原根为3.
P = 1004535809 = 479*221+1, 能够处理221 = 2e6+ 规模的数据,原根为3, 且 1004535809 加起来不会爆 int.
NTT能解决模数 P = r⋅2k +1 的问题,那么如何解决模任意数呢?
先前的 NTT资料 里有提到,
即用多个小素数跑NTT,最后用中国剩余定理求出 n(m-1)2 内满足条件的唯一值,当 各个素数积 > n(m-1)2 时中国剩余定理后显然可取得唯一值。
=================================分割线===================================
Ck = ∑i⊕j=k (Ai*Bj), ⊕是某种运算符号。当⊕是+时,即是傅里叶变换;当⊕是^, &, |等某种位运算时,即是FWT快速沃尔什变换。
FFT中,数组长度要大于结果的最高次幂,高位补0;FWT时,数组长度需要是2的整数次幂,不足补0。
原理不是怎么重要...
模板套用即可。
//快速沃尔什变换
void FWT(int*a,int n){
for(int d=;d<n;d<<=)for(int m=d<<,i=;i<n;i+=m)for(int j=;j<d;j++){
int x=a[i+j],y=a[i+j+d];
//xor:a[i+j]=x+y,a[i+j+d]=x−y;
//and:a[i+j]=x+y;
//or:a[i+j+d]=x+y;
}
}
void UFWT(int*a,int n){
for(int d=;d<n;d<<=)for(int m=d<<,i=;i<n;i+=m)for(int j=;j<d;j++){
int x=a[i+j],y=a[i+j+d];
//xor:a[i+j]=(x+y)/2,a[i+j+d]=(x−y)/2;
//and:a[i+j]=x−y;
//or:a[i+j+d]=y−x;
}
}
防溢出可mod 1e9+7大质数,则除以2的时候乘2的逆元。
FWT后,相乘,UFWT回去即可。
卷积FFT、NTT、FWT的更多相关文章
- [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)
目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...
- $FFT/NTT/FWT$题单&简要题解
打算写一个多项式总结. 虽然自己菜得太真实了. 好像四级标题太小了,下次写博客的时候再考虑一下. 模板 \(FFT\)模板 #include <iostream> #include < ...
- FFT \ NTT总结(多项式的构造方法)
前言.FFT NTT 算法 网上有很多,这里不再赘述. 模板见我的代码库: FFT:戳我 NTT:戳我 正经向:FFT题目解题思路 \(FFT\)这个玩意不可能直接裸考的..... 其实一般\(FF ...
- FFT&NTT总结
FFT&NTT总结 一些概念 \(DFT:\)离散傅里叶变换\(\rightarrow O(n^2)\)计算多项式卷积 \(FFT:\)快速傅里叶变换\(\rightarrow O(nlogn ...
- 快速构造FFT/NTT
@(学习笔记)[FFT, NTT] 问题概述 给出两个次数为\(n\)的多项式\(A\)和\(B\), 要求在\(O(n \log n)\)内求出它们的卷积, 即对于结果\(C\)的每一项, 都有\[ ...
- FFT/NTT初探
做了全家桶然后写了几道入门题. FFT.ref NTT.ref Luogu4238 [模板]多项式求逆 Link 套牛顿迭代完事.有一个细节问题是:这次运算多项式有几项就只赋几项的值,其他位置(次数大 ...
- FFT/NTT基础题总结
在学各种数各种反演之前把以前做的$FFT$/$NTT$的题整理一遍 还请数论$dalao$口下留情 T1快速傅立叶之二 题目中要求求出 $c_k=\sum\limits_{i=k}^{n-1}a_i* ...
- FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ
众所周知,tzc 在 2019 年(12 月 31 日)就第一次开始接触多项式相关算法,可到 2021 年(1 月 1 日)才开始写这篇 blog. 感觉自己开了个大坑( 多项式 多项式乘法 好吧这个 ...
- FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅲ
第三波,走起~~ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅱ 单位根反演 今天打多校时 1002 被卡科技了 ...
- FFT/NTT/MTT学习笔记
FFT/NTT/MTT Tags:数学 作业部落 评论地址 前言 这是网上的优秀博客 并不建议初学者看我的博客,因为我也不是很了解FFT的具体原理 一.概述 两个多项式相乘,不用\(N^2\),通过\ ...
随机推荐
- 关于基于webrtc的android-apk 和 webrtc-brows
这一段时间我在做一些关于基于webrtc应用的一些研究,做个一个android的demo,详情如下: 手机客户端: 基于webrtc的 android apk (webrtc 代码版本 R67 ...
- (POJ2635)The Embarrassed Cryptographer(大数取模)
The Embarrassed Cryptographer Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13041 Accep ...
- c#中的委托和事件(转)
引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...
- 花40分钟写一个-CBIR引擎-代码公开
浏览网页的时候发现一篇不错的文章"用Python和OpenCV创建一个图片搜索引擎的完整指南"http://python.jobbole.com/80860/.作者在浏 ...
- Unix网络编程--卷一:套接字联网API
UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...
- CountDownLatch的原理学习
转载:http://blog.csdn.net/yanyan19880509/article/details/52349056 前言 前面介绍了ReentrantLock,又叫排他锁,本篇主要通过Co ...
- UML的概念模型
为 了理解UML,需要形成该语言的概念模型,这要求学习建模的3个要素:UML的基本构造块.支配这些构造块如何放在一起的规则和一些运用于整个UML的公 共机制.如果掌握了这些思想,就能够读懂UML模型, ...
- [美]莫提默 J. 艾德勒《如何阅读一本书》
我最近在阅读一本书,这本书的书名叫<如何阅读一本书>(商务出版社,2015),顾名思义. 作者认为,阅读是一件跟写书一样复杂的活动,而许多人并不会阅读. 看过后,你可能会有“我真没 ...
- CSS3那些不为人知的高级属性
尽管现代浏览器已经支持了众多的CSS3属性,但是大部分设计师和开发人员貌似依然在关注于一些很“主流”的属性,如border-radius.box-shadow或者transform等.它们有良好的文档 ...
- sql通用分页自定义表条件存储过程
create PROCEDURE PrcTestByPage ( @tablename varchar(50), @selectfilter varchar(100), @orderbyfilter ...

