FFT,NTT 专题
学习傅里叶的基本性质及其代码,可以参考大神理解
还有 ACdream 的博客
贴一下NTT的模板:
using namespace std;
typedef long long ll; int n;
const ll MOD=;
const int N = ;
const int g=;
int len;
ll A[N];
long long a[N],b[N],wn[];
long long q_pow(long long x,long long y,long long P)
{
long long ans=;
while(y>)
{
if(y&)ans=ans*x%P;
x=x*x%P;
y>>=;
}
return ans;
}
void init()
{
for(int i=;i<;i++)
{
int t=<<i;
wn[i]=q_pow(g,(MOD-)/t,MOD);
}
}
///雷德算法,2^M=len,将第i位的数与“i的二进制反转之后的位”的数交换
void rader(long long F[],int len)
{
int j=len/;///模拟二进制反转进位的的位置
for(int i=;i<len-;i++)
{
if(i<j)swap(F[i],F[j]);///该出手时就出手
int k=len/;
while(j>=k)
{
j-=k;
k>>=;
}
if(j<k)j+=k;
}
}
void NTT(long long F[],int len,int t)
{
int id=;
rader(F,len);
for(int h=;h<=len;h<<=)
{
id++;
for(int j=;j<len;j+=h)
{
long long E=;
for(int k=j;k<j+h/;k++)
{
long long u=F[k];
long long v=(E*F[k+h/])%MOD;
F[k]=(u+v)%MOD;
F[k+h/]=((u-v)%MOD+MOD)%MOD;
E=(E*wn[id])%MOD;
}
}
}
if(t==-)
{
for(int i=;i<len/;i++)swap(F[i],F[len-i]);
long long ni=q_pow(len,MOD-,MOD);
for(int i=;i<len;i++)F[i]=(F[i]%MOD*ni)%MOD;
}
} void work()///卷积,点乘,插值
{
NTT(a,len,);
NTT(b,len,);
for(int i=;i<len;i++)
a[i]=(a[i]*b[i])%MOD;
NTT(a,len,-);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
init();
int T_T;
scanf("%d",&T_T);
for(int kase=;kase<=T_T;kase++)
{
sc(n);
len=;
while(len<=*n)
len<<=;
/**
这部分就是你对公式的变形并把他转化为卷积形式,分别存在a[],b[]里
*/
work();
}
return 0;
}
对于傅里叶运用的要点,要认真对待对下面卷积公式的理解
训练:
传送门:hdu 5829 Rikka with Subset
题意:给你一个数组A[],然后计算F[k],F[k]指A[]所有子集中,先对每个子集前k大的数的和,然后再对把所以子集所求值求和
思路:因为我也是初学,所以我找的一个大神的博客学习的http://blog.csdn.net/cqu_hyx/article/details/52194696
对于其中的几点,我做一点补充:
- f[k]计算的是第k大的数对答案的贡献,而比他大的数的贡献没有计算;不过只需要累加分f[1]..f[k-1]就是前k大的数的和了
- 对比以上卷积公式,我们得到的是 a[i]=2n-i/i! , b[i]=A[i]*(i-1)! ;如果我们b[0]=A[1]*0!,那么我们reverse一下,b[i]=b[n-i]了;在我们推导的f[k]公式里,f[k]是与a[i]*b[i+k]相关的,且i最大为(n-k),经过我们对b数组reverse,f[k]是与a[i]*b[(n-k)-i]相关的,这刚好和上面的卷积公式一致,所以我们可以放心ntt了。
- 由卷积公式可知,y[n-k]是a[i]*b[(n-k)-i]的卷积结果,而这个结果存在a[]里;并且f[k]也等于a[i]*b[(n-k)-i]的卷积,所以f[k]与y[n-k]即a[n-k]相关
/**************************************************************
Problem:hdu 5829 Rikka with Subset
User: youmi
Language: C++
Result: Accepted
Time:2605MS
Memory:11804K
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#include <cmath>
#include <queue>
#include <deque>
#include <string>
#include <vector>
#define zeros(a) memset(a,0,sizeof(a))
#define ones(a) memset(a,-1,sizeof(a))
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define sclld(a) scanf("%I64d",&a)
#define pt(a) printf("%d\n",a)
#define ptlld(a) printf("%I64d\n",a)
#define rep(i,from,to) for(int i=from;i<=to;i++)
#define irep(i,to,from) for(int i=to;i>=from;i--)
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define lson (step<<1)
#define rson (lson+1)
#define eps 1e-6
#define oo 0x3fffffff
#define TEST cout<<"*************************"<<endl
const double pi=*atan(1.0); using namespace std;
typedef long long ll; int n;
const ll MOD=;
const int N = ;
const int g=;
int len;
ll inv2;
ll A[N];
ll inv[N],fac[N],f[N],bit[N];
long long a[N],b[N],wn[];
long long q_pow(long long x,long long y,long long P)
{
long long ans=;
while(y>)
{
if(y&)ans=ans*x%P;
x=x*x%P;
y>>=;
}
return ans;
}
void init()
{
for(int i=;i<;i++)
{
int t=<<i;
wn[i]=q_pow(g,(MOD-)/t,MOD);
}
inv[]=inv[]=;
rep(i,,1e5)
inv[i]=(inv[i-]*q_pow(i,MOD-,MOD))%MOD;
fac[]=fac[]=;
rep(i,,1e5)
fac[i]=(fac[i-]*i)%MOD;
bit[]=;
rep(i,,1e5)
bit[i]=bit[i-]*%MOD;
inv2=q_pow(,MOD-,MOD);
}
///雷德算法,2^M=len,将第i位的数与“i的二进制反转之后的位”的数交换
void rader(long long F[],int len)
{
int j=len/;///模拟二进制反转进位的的位置
for(int i=;i<len-;i++)
{
if(i<j)swap(F[i],F[j]);///该出手时就出手
int k=len/;
while(j>=k)
{
j-=k;
k>>=;
}
if(j<k)j+=k;
}
}
void NTT(long long F[],int len,int t)
{
int id=;
rader(F,len);
for(int h=;h<=len;h<<=)
{
id++;
for(int j=;j<len;j+=h)
{
long long E=;
for(int k=j;k<j+h/;k++)
{
long long u=F[k];
long long v=(E*F[k+h/])%MOD;
F[k]=(u+v)%MOD;
F[k+h/]=((u-v)%MOD+MOD)%MOD;
E=(E*wn[id])%MOD;
}
}
}
if(t==-)
{
for(int i=;i<len/;i++)swap(F[i],F[len-i]);
long long ni=q_pow(len,MOD-,MOD);
for(int i=;i<len;i++)F[i]=(F[i]%MOD*ni)%MOD;
}
} void work()///卷积,点乘,插值
{
NTT(a,len,);
NTT(b,len,);
for(int i=;i<len;i++)
a[i]=(a[i]*b[i])%MOD;
NTT(a,len,-);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
init();
int T_T;
scanf("%d",&T_T);
for(int kase=;kase<=T_T;kase++)
{
sc(n);
len=;
while(len<=*n)
len<<=;
rep(i,,n)
sclld(A[i]);
sort(A+,A++n,greater<ll>());
zeros(a);zeros(b);
rep(i,,n-)
a[i]=(bit[n-i]*inv[i])%MOD;
rep(i,,n-)
b[i]=(A[i+]*fac[i])%MOD;
reverse(b,b+n);
work();
ll r=inv2;
f[]=;
rep(i,,n)
{
f[i]=a[n-i]*inv[i-]%MOD*r%MOD;
r=r*inv2%MOD;
f[i]=(f[i]+f[i-])%MOD;
printf("%I64d ",f[i]);
}
puts("");
}
}
FFT,NTT 专题的更多相关文章
- FFT与NTT专题
先不管旋转操作,考虑化简这个差异值 $$begin{aligned}sum_{i=1}^n(x_i-y_i-c)^2&=sum_{i=1}^n(x_i-y_i)^2+nc^2-2csum_{i ...
- FFT \ NTT总结(多项式的构造方法)
前言.FFT NTT 算法 网上有很多,这里不再赘述. 模板见我的代码库: FFT:戳我 NTT:戳我 正经向:FFT题目解题思路 \(FFT\)这个玩意不可能直接裸考的..... 其实一般\(FF ...
- [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)
目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...
- FFT/NTT/MTT学习笔记
FFT/NTT/MTT Tags:数学 作业部落 评论地址 前言 这是网上的优秀博客 并不建议初学者看我的博客,因为我也不是很了解FFT的具体原理 一.概述 两个多项式相乘,不用\(N^2\),通过\ ...
- 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模板 既 HDU1402 A * B Problem Plus
@(学习笔记)[FFT, NTT] Problem Description Calculate A * B. Input Each line will contain two integers A a ...
- FFT/NTT基础题总结
在学各种数各种反演之前把以前做的$FFT$/$NTT$的题整理一遍 还请数论$dalao$口下留情 T1快速傅立叶之二 题目中要求求出 $c_k=\sum\limits_{i=k}^{n-1}a_i* ...
- $FFT/NTT/FWT$题单&简要题解
打算写一个多项式总结. 虽然自己菜得太真实了. 好像四级标题太小了,下次写博客的时候再考虑一下. 模板 \(FFT\)模板 #include <iostream> #include < ...
- FFT&NTT数学解释
FFT和NTT真是噩梦呢 既然被FFT和NTT坑够了,坑一下其他的人也未尝不可呢 前置知识 多项式基础知识 矩阵基础知识(之后会一直用矩阵表达) FFT:复数基础知识 NTT:模运算基础知识 单位根介 ...
随机推荐
- 2015年免费的25款 WordPress 网站模板
2015年 WordPress 插件和主题的数量继续在增长.这一年,我们可以期待WP主题引入一些新的技术,从背景,自适应响应式图像到从背景图片中提取主色. 本文包含25款最近发布的 WordPress ...
- JavaScript入门篇QA总结
Q1:JS可以放在哪个位置?A1:1.放在<head>标签中,用<script type="text/javascript"></script> ...
- go语言循环语句 for
Go语言中的循环语句只支持for关键字,而不支持while和do-while结构. sum := 0 for i := 0; i < 10; i++ { sum += i } 无限循环的写法: ...
- Python统计学技术环境
http://www.lfd.uci.edu/~gohlke/pythonlibs/#sympy 1.1. Python 1.1.1. NumPy pip install numpy-1.11.0+m ...
- 图文详细解说DevExpress 2015新版亮点【附文档下载】
历时两个月,翻译自官网的更新说明文档,最后整理成册,文末附PDF地址. DevExpress 在今年6月份发布了正式的2015版本,2015在旧版基础上有明显的升级改进,尤其是DevExtreme.W ...
- 智者当借力而行, 借助Autodesk应用程序商店实现名利双收
有没有注意到这个"精选应用"菜单?有没有想过这个菜单下的应用是从哪里来的?你的应用也可以出现在这里哦~ 如果你还不知道,Autodesk在几年前就发布了Autodesk应用程序商店 ...
- Linux下EclipseCDT工程和TFS的持续集成CI实践
在Linux下使用TFS自动构建,需要自动执行连接tfs服务器的操作,命令行文件包TEE-CLC-10.1.0.2011121402.zip,下载地址:http://www.microsoft.com ...
- swift 中手势的使用
swift 中手势的使用 /**点击手势*/ func tapGestureDemo() { //建立手势识别器 let gesture = UITapGestureRecognizer(target ...
- Android 数据库SQLite 写入SD卡
如果手机没有root,数据库文件是无法查看到的,不方便调试. 最好的办法是把数据库写进SD卡. 修改的地方有两处: 1.在你的helper类中把数据库文件名称 DATABASE_NAME 由原来的一个 ...
- UITextField限制中英文字数和光标定位以及第三方输入限制问题
先自定义一个UITextField的子类HLNavTextField,在控制器里调用子类的- (void)limitHansLength:(int)hans otherLength:(int)othe ...