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:模运算基础知识 单位根介 ...
随机推荐
- Immutable.js – JavaScript 不可变数据集合
不可变数据是指一旦创建就不能被修改的数据,使得应用开发更简单,允许使用函数式编程技术,比如惰性评估.Immutable JS 提供一个惰性 Sequence,允许高效的队列方法链,类似 map 和 f ...
- go git 安装配置与使用 (windows 7 64bit)
go语言安装使用第三方库方式一般采用 go get github.com/.../... 命令.例如: go get github.com/astaxie/beego 1.错误情况一: packag ...
- 原生JS:Date对象详细参考
Date对象:基于1970年1月1日(世界标准时间)起的毫秒数 本文参考MDN做的详细整理,方便大家参考MDN 构造函数: new Date(); 依据系统设置的当前时间来创建一个Date对象. ne ...
- CSS3动画(个人理解)
随着学习的深入,越来越觉得Css3动画的重要,虽然JQ自定义动画和动画回调函数必须掌握,但是css3动画做起来更加绚丽,更加方便!1.常规使用1.1 使用transition属性,一般我们是配合hov ...
- HTML <base> 标签 为页面上的所有链接规定默认地址或默认目标
定义和用法 <base> 标签为页面上的所有链接规定默认地址或默认目标. 通常情况下,浏览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白. 使用 <base& ...
- ReCap 360 photo照片建模技术的又一个例子
这是我做的又一个利用Autodesk ReCap 360 照片建模技术做的一个例子.你可以下载模型自己把玩,或者下载原始照片自己试一试. 拍摄工具: 小米手机 照片数量:约120张 后期处理工具: p ...
- 如何让光标处于EditText的末尾
经测试发现,如果EditText预先有内容,光标自然会在文字的末尾 . 但是如果预先内容为空,然后设置好内容,这种情况下光标自然会在文字的开头,所以这种情况下可以这样做让光标位于末尾: editTex ...
- mysql 数据库服务中的应用程序
mysql 是一个数据库服务,而实现数据库服务是由mysql中的很多子应用程序来完成的(http://dev.mysql.com/doc/refman/5.7/en/programs-overview ...
- java你可能不知道的事(2)--堆和栈
在java语言的学习和使用当中你可能已经了解或者知道堆和栈,但是你可能没有完全的理解它们.今天我们就一起来学习堆.栈的特点以及它们的区别.认识了这个之后,你可能对java有更深的理解. Java堆内存 ...
- 【原+转】用CMake代替makefile进行跨平台交叉编译
在开始介绍如何使用CMake编译跨平台的静态库之前,先讲讲我在没有使用CMake之前所趟过的坑.因为很多开源的程序,比如png,都是自带编译脚本的.我们可以使用下列脚本来进行编译: ./configu ...