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:模运算基础知识 单位根介 ...
随机推荐
- scroll事件实现监控滚动条并分页显示示例(zepto.js)
scroll事件实现监控滚动条并分页显示示例(zepto.js ) 需求:在APP落地页上的底部位置显示此前其他用户的购买记录,要求此div盒子只显示3条半,但一页有10条,div内的滑动条滑到一页 ...
- JavaScript学习笔记2之Tab切换
1.Tab切换简写版1 页面布局如下: <div id="tab"> <h1 id="title"> <span class=&q ...
- 利用JSONP实现跨域请求
前言:有时候一忙起来就没了时间观念,原来我已经有十多天没写博客了.一直想做跨域方面的尝试,无奈最近准备校招没时间动动手.今天就先讲讲JSONP吧,昨晚还在研究QQ空间日志里面网络图片的问题呢,我发现日 ...
- abap 字符串处理
1).SHIFT:截断字符串 SHIFT {c} [BY {n} PLACES] [{mode}].: 作用:去掉字符串的前n个位置的字符,如果n未指定,默认为1,如果指定的n小于等于0,则 ...
- 刷新ALV定位到当前记录行
如果使用"REFRESH_TABLE_DISPLAY"刷新ALV后,记录会跳到第一行,以下代码可以使记录仍然定位在当前行 DATA ls_stable TYPE lvc_s_stb ...
- Android九宫格界面实现点击每个格点击跳转界面
刚开始有个任务就是做一个九宫格界面,后来有个任务就是实现点击每个格并跳转界面实现每个格的功能.下面我就介绍一下我是如何实现该功能的 首先写一下我的想法是: 登录成功后显示一个九宫格界面,每个九宫格的每 ...
- Android 调用系统照相机拍照和录像
本文实现android系统照相机的调用来拍照 项目的布局相当简单,只有一个Button: <RelativeLayout xmlns:android="http://schemas.a ...
- iOS 远程推送通知
1.什么是推送通知 在某些特殊情况下,应用程序被动收到的以不同种界面形式出现的提醒信息 推送通知的作用:可以让不在前台运行的app通知app发生了改变 iOS中得推送通知种类 远程推送通知(Remot ...
- npm常用命令小结
目录(更新于2016.09.23): 1.认识和使用NPM 2.npm包安装模式 3.npm包管理(package的安装.卸载.升级.查看.搜索.发布,其他等) npm install [-g] 本地 ...
- 测试必备技能系列1 :通过mysql命令进行脚本数据导入
老徐,分享测试项目中实际能解决问题的干货! 今日分享: 如何通过mysql命令行,导入mysql脚本文件数据? ----- 解决实际的问题: 工作过程中,经常需要导入mysql脚本文件 很多同 ...