fft练习
数学相关一直都好弱啊>_<
窝这个月要补一补数学啦, 先从基础的fft补起吧!
现在做了 道。
窝的fft 模板 (bzoj 2179)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define MAXN 200005
#define PI M_PI
using namespace std;
struct CP{
double x, y;
CP(){}
CP(double x, double y) : x(x), y(y) {}
inline CP operator+ (CP b) {return CP(x+b.x, y+b.y);}
inline CP operator- (CP b) {return CP(x-b.x, y-b.y);}
inline CP operator* (CP b) {return CP(x*b.x-y*b.y, x*b.y+y*b.x);}
}a[MAXN], b[MAXN], A[MAXN], x, y;
int n, N, l, dig[MAXN], ans[MAXN];
char s1[MAXN], s2[MAXN];
inline void dft(CP *a, int n, int f){
for(int i = ; i < n; i ++) A[i] = a[dig[i]];
for(int i = ; i < n; i ++) a[i] = A[i];
for(int i = ; i <= n; i <<= ){
CP wn(cos(*PI/i), f*sin(*PI/i));
for(int k = ; k < n; k += i){
CP w(, );
for(int j = ; j < i/; j ++) x = a[k+j], y = w*a[k+j+i/], a[k+j]=x+y, a[k+j+i/] = x-y, w = w*wn;
}
}
}
int main(){
scanf("%d%s%s", &n, s1, s2);
for(int i = ; i < n; i ++) a[i].x = s1[n-i-]-'', b[i].x = s2[n-i-]-'';
for(N = , l = ; N < n; N <<= , l ++); N <<= , l ++;
for(int i = ; i < N; i ++){
int ret = , p = i;
for(int j = ; j <= l; j ++) ret <<= , ret += (p&), p >>= ;
dig[i] = ret;
}
dft(a, N, ), dft(b, N, );
for(int i = ; i < N; i ++) a[i] = a[i]*b[i];
dft(a, N, -);
for(int i = ; i < N; i ++) ans[i] = (int)(a[i].x / N + 0.5);
for(int i = ; i < N; i ++) ans[i+] += ans[i]/, ans[i] %= ;
l = N; while(l > && ans[l-] == ) l --;
for(int i = l-; i >= ; i --) printf("%d", ans[i]); cout << endl;
return ;
}
BZOJ 2194
之前做过的啦,求 c_k = Σ(a_i * b_(i-k)) (k <= i)
标准的差积形式是 i + j 一定, 现在的式子要求 i - j 一定, 容易想到把所有b的下标都乘以-1原式即转化为i+j一定了, 为了方便处理可以把所有b再加上n使得下标为非负数,即把b_i 变为 b_(n-i) 。
tips: 卷积的形式并不一定只是 k = i+j, 还有可能是 k = i-j 或者 …………
bzoj 3527: [Zjoi2014]力
之前做过的啦。 不打式子了, 是个人都会把qi乘进去, 然后原式就变成了求 E_i = Σqj/((i-j)^2) (j<i) - Σqj/((i-j)^2) (j>i)
我第一次做的时候并没有看出来这是个卷积QAQ 蠢死了QAQ
我们可以设 一个 函数 f(x) = q_x, g(x) = 1/(x^2), 然后那个式子的前一项不就是 f 和 g 的卷积了吗! 第二个式子是 当 i-j一定时候的情况, 那不就是上一题 bzoj 2194了吗,,,,然后就没了。
tips:不要拘泥于已有的数列,可以根据题目自己构造出新的函数, 需要求 F_i = Σ( f(j) 乘或除以 g(i±j) ) 的时候很有可能是卷积!!!看到 j 和 i±j 这类的关键词就应该往这边多想一想。
BZOJ 3771 Triple
之前做过的啦。给定n个物品,可以用一个/两个/三个不同的物品凑出不同的价值,求每种价值有多少种拼凑方案(顺序不同算一种) (题目大意来自popoqqq)
自己还是没有想到QAQ
这个要构建一个母函数。初步地感受母函数的应用:如果我们可以快速地计算出一次操作后每种效果有多少种产生方案(0/1),并且多次操作的效果是可以累加的,那么在用fft优化以后(效果的累加不就是卷积吗)可以比较快速地(k*nlogn)计算出k次操作后每种效果有多少种产生方案 (怎么觉得我在说的是用快速幂优化的矩阵乘法啊。。。。。)感觉的确和矩乘有点像, 不过矩乘的每次操作的状态是一个二维的数组, 因为在不同的点可以进行的操作不同, 但是 母函数只需要求出一个一维数组, 因为在应用母函数的时候当前状态 并不会影响下一步的操作
(以上皆是窝自己的口胡,等我读完具体数学的 "生成函数" 一章后再来总结吧QAQ)
tips: 见上
BZOJ 3160 万径人踪灭
给出一个只含有a和b的字符串, 求有多少个至少有一个断点(即不完全连续)的回文子序列,要求子序列选出来的每一个的位置同样必须关于任意一个位置或中缝对称。
考虑以每一个点i为中间的点所组成的符合要求的子序列,对于每一个j, 如果 s[i-j] == s[i+j] 则可以把这对字符加到子序列里, 当然也可以不加, 显然对于不同的j, 每一对字符是相互独立的, 所以以i为中点的贡献就是 2^(s[i-j]==s[i+j]的数量), 注意因为子序列不可以完全连续所以还要再减去一个可以直接manachar求出来的完全连续的回文串数量。 所以现在唯一剩下的问题就是对于每一个i, Σ (s[i-j] == s[i+j]), 因为只有a, b两种字符, 显然可以拆开来算, 设数组A使得 A_i = (s[i] == 'a'), 则字符a对于以i为中心贡献就是 Σ (s[j]*s[2*i-j]) , 这个显然就是一个卷积啦。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define ll long long
#define mod 1000000007
#define MAXN 1000005
#define PI M_PI
using namespace std;
char s[MAXN];
int N, L, len, r[MAXN], rev[MAXN];
ll ans = mod;
ll mypow(ll x, int k){
ll ret = ;
while(k){
if(k&)(ret *= x) %= mod;
(x*=x)%=mod; k >>= ;
}return ret;
}
struct CP{
double x, y;
CP () {}
CP (double x, double y) : x(x), y(y) {}
inline CP operator+ (CP b){return CP(x+b.x, y+b.y);}
inline CP operator- (CP b){return CP(x-b.x, y-b.y);}
inline CP operator* (CP b){return CP(x*b.x-y*b.y, x*b.y+y*b.x);}
}A[MAXN], B[MAXN], T[MAXN], x, y;
void dft(CP *a, int n, int f){
for(int i = ; i < n; i ++) T[i] = a[rev[i]];
for(int i = ; i < n; i ++) a[i] = T[i];
for(int i = ; i <= n; i <<= ){
CP wn(cos(PI*/i), f*sin(PI*/i));
for(int j = ; j < n; j += i){
CP w(, );
for(int k = ; k < i/; k ++)
x = a[j+k], y = w*a[j+k+i/], a[j+k] = x+y, a[j+k+i/] = x-y, w = w*wn;
}
}
}
int main(){
scanf("%s", s + );
len = strlen(s+);
for(int i = len; i >= ; i --) s[i+i] = s[i], s[i+i-] = '*';
s[] = '&'; s[len+len+] = '*'; s[len+len+] = '#';
int k = ; r[] = r[] = ;
for(int i = ; i <= len+len; i ++){
r[i] = max(min(k+r[k]-i, r[k-(i-k)]), );
while(i-r[i]> && s[i+r[i]] == s[i-r[i]]) r[i] ++;
if(i+r[i] > k+r[k]) k = i;
// printf("!!! %d %d\n", i, r[i]/2);
ans -= r[i]/;
if(ans < ) ans += mod;
}
// cout << ans << endl;
int n = len+len;
for(int i = ; i <= n; i ++) A[i].x = (s[i]=='a'), B[i].x = (s[i]=='b');
for(N=, L=; N <= n; N<<=, L ++); N <<= , L ++;
for(int i = ; i < N; i ++){
int ret = , p = i;
for(int j = ; j <= L; j ++) ret <<= , ret += (p&), p >>= ;
rev[i] = ret;
}
dft(A, N, ); dft(B, N, );
for(int i = ; i < N; i ++) A[i] = A[i]*A[i] + B[i]*B[i];
dft(A, N, -);
for(int i = ; i < N; i ++){
(ans += mypow(, ((ll)(A[i].x/N+0.5)+)>>)-) %= mod;
// printf("%d %I64d\n", i, (ll)(A[i].x/N+0.5));
}
cout << ans << endl;
//system("pause");
return ;
}
hdu 4509 3-idiot
给你三根线段, 问你有多少种可以组成三角形的方法。
做过bzoj3771后这题就是一眼题了QAQ 类似地,对于边长建出一个生成函数然后卷积一次算出由两条边组成的长度和为x的线段组有多少组然后再扫一遍第三条边就可以了。
BZOJ 3992 Sdoi2015 序列统计
给你一个包含了S个数的模M意义下的集合,问只用集合中的数组成一个长度为N的序列使得序列中所有数的乘积为X的方案数有多少种。
模意义下的乘积显然可以求一个原根搞成指标的形式,于是就变成一堆数的和的形式了, 直接上裸的FFT就好, 因为这道题要求取模且模数又是一个X*2^p+1形式的数所以把FFT写成数论版的就可以了。
BZOJ 3456 城市规划
编号是很优美的3456哦~
求出n个点的简单(无重边无自环)无向连通图数目.
递推式就是串珠子那道题嘛,枚举最小点所在连通块大小然后算出不连通的方案数再容斥一下就好了 fi = 2C(2,i) - ∑(j = 1~(i-1)) fj* C(j-1, i-1) * 2C(2,i-j)
把C(j-1,i-1) 拆了然后把 (i-1)!这一项提出来, 显然就是一个卷积了。
因为这里每一步的卷积会用到之前的结果, 1~i-1中的每一个结果都会对fi产生贡献, 用cdq分治的思想搞一下就可以了。work(l,r)计算出l~r中每一个数的f值。先调用work(l,mid)得到l~mid中每一个f值,然后算出 l~mid中所有数对 mid+1~r的贡献, 最后再调用 work(mid+1,r)就可以了。其中 l~mid 对 mid+1到r的贡献做一次多项式乘法就可以一起求出来啦!
分治 + fft , O(nlog2n)。 很好理解代码也很好写。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mod 1004535809
#define MAXN 300005
#define G 3
#define ll long long
using namespace std;
int n, inv2[MAXN], inv[MAXN], fac[MAXN], infac[MAXN], T[MAXN], f[MAXN], A[MAXN], B[MAXN], tmp[MAXN], rev[MAXN];
int mypow(int x, int k){
int ans = ;
while(k){
if(k&) ans = (ll)ans*x%mod;
x = (ll)x*x%mod; k >>= ;
} return ans;
}
void dft(int *a, int n, int f){
for(int i = ; i < n; i ++) tmp[i] = a[rev[i]];
for(int i = ; i < n; i ++) a[i] = tmp[i];
for(int i = ; i <= n; i <<= ){
ll w = mypow(G, ((ll)f*(mod-)/i)%(mod-));
for(int j = ; j < n; j += i){
ll wn = ;
for(int k = ; k < i/; k ++){
ll x = a[j+k], y = (wn*a[j+k+i/])%mod;
a[j+k] = (x+y)%mod, a[j+k+i/] = (x-y+mod)%mod; (wn*=w)%=mod;
}
}
}
}
void solve(int l, int r){
if(l == r){
f[l] = (T[l] - (ll) fac[l-] * f[l] % mod + mod) % mod; return;
}
int mid = l + r >> , nn = max(mid-l+, r-mid);
solve(l, mid);
int N, L;
for(N=,L=; N<=nn; N<<=, L++); N<<=, L++;
for(int i = ; i < N; i ++){
int ret = , p = i;
for(int j = ; j <= L; j ++) ret <<= , ret += (p&), p >>= ;
rev[i] = ret;
}
for(int i = ; i < N; i ++) A[i] = B[i] = ;
for(int i = l; i <= mid; i ++) A[i-l] = (ll) f[i] * infac[i-] % mod;
for(int i = ; i <= r-l; i ++) B[i] = (ll) T[i] * infac[i] % mod;
dft(A, N, ); dft(B, N, );
for(int i = ; i < N; i ++) A[i] = (ll)A[i]*B[i] % mod;
dft(A, N, mod-);
for(int i = mid+; i <= r; i ++) (f[i] += (ll)A[i-l] * inv[N] % mod) %= mod;
solve(mid+, r);
}
int main(){
scanf("%d", &n);
int N, l;
for(N=,l=; N<=n; N<<=, l++); N<<=, l ++;
inv2[] = , inv2[] = mypow(, mod-);
for(int i = ; i <= N; i ++) inv2[i] = (ll)inv2[i-]*inv2[] % mod;
for(int i = ; i <= N; i ++) inv[i] = mypow(i, mod-);
fac[] = infac[] = ;
for(int i = ; i <= N; i ++) fac[i] = (ll)fac[i-]*i%mod, infac[i] = (ll)infac[i-]*inv[i]%mod;
for(int i = ; i <= N; i ++) T[i] = mypow(, (((ll)i*(i-))/)%(mod-));
solve(, n);
printf("%d\n", f[n]);
return ;
}
当然这道题有更简单的 O(nlogn) 的多项式求逆元的做法。
codeforces #250E The Child and Binary Tree
Picks博客上面讲的多项式开根练习题。
bzoj 上面卡不过去QAQ
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define ll long long
#define MAXN 500005
#define mod 998244353
#define G 3
#define inv_2 499122177
using namespace std;
int N, L, n, m, c[MAXN], d[MAXN], rev[MAXN], T[MAXN];
int mypow(int x, int k){
int ret = ;
while(k){
if(k&) ret = ((ll)ret*x)%mod;
x = (ll)x*x%mod; k >>= ;
}return ret;
}
void dft(int *a, int n, int f){
for(int i = ; i < n; i ++) T[i] = a[rev[i]];
for(int i = ; i < n; i ++) a[i] = T[i];
for(int i = ; i <= n; i <<= ){
ll w = mypow(G, ((ll)f*(mod-)/i) % (mod-));
for(int j = ; j < n; j += i){
ll wn = ;
for(int k = ; k < (i>>); k ++){
ll x = a[j+k], y = wn * a[j+k+(i>>)] % mod;
a[j+k] = (x+y)%mod, a[j+k+(i>>)] = (x-y+mod)%mod, (wn *= w) %= mod;
}
}
}
}
void getinv(int *a, int *b, int n){
static int tmp[MAXN];
if(n == ) {b[] = mypow(a[], mod-); return;}
getinv(a, b, n>>);
memcpy(tmp, a, n*);
memset(tmp+n, , n*); int l = , tt = n<<, NN = n<<;
while(tt) tt >>= , l ++; l --;
for(int i = ; i < NN; i ++){
int la = , p = i;
for(int j = ; j < l; j ++) la <<= , la += (p&), p >>= ;
rev[i] = la;
} dft(tmp, NN, );
dft(b, NN, );
for(int i = ; i < NN; i ++)
tmp[i] = (ll)b[i] * (-(ll)tmp[i]*b[i]%mod + mod)%mod;
dft(tmp, NN, mod-);
ll inv = mypow(NN, mod-);
for(int i = ; i < n; i ++)
b[i] = tmp[i] * inv % mod;
memset(b+n, , n*);
}
void getsqrt(int *a, int *b, int n){
static int tmp[MAXN], b_in[MAXN];
if(n == ) {b[] = ; return;}
getsqrt(a, b, n>>);
memset(b_in, , n*);
getinv(b, b_in, n);
memcpy(tmp, a, n*);
memset(tmp+n, , n*); int l = , tt = n<<, NN = n<<;
while(tt) tt >>= , l ++; l --;
for(int i = ; i < NN; i ++){
int la = , p = i;
for(int j = ; j < l; j ++) la <<= , la += (p&), p >>= ;
rev[i] = la;
} dft(tmp, NN, );
dft(b, NN, );
dft(b_in, NN, );
for(int i = ; i < NN; i ++)
tmp[i] = ((ll) inv_2 * (b[i] + (ll)tmp[i]*b_in[i] % mod)) % mod;
dft(tmp, NN, mod-);
ll inv = mypow(NN, mod-);
for(int i = ; i < n; i ++)
b[i] = tmp[i]*inv%mod;
memset(b+n, , n*);
}
int main(){
scanf("%d%d", &n, &m);
for(N=,L=; N<=m; N<<=, L++);
for(int i = ; i <= n; i ++){
int x; scanf("%d", &x);
c[x] -= ;
if(c[x] < ) c[x] += mod;
}
c[] = ;
getsqrt(c, d, N);
static int C[MAXN], D[MAXN];
memcpy(C, d, N*);
(++ C[]) %= mod;
getinv(C, D, N);
for(int i = ; i <= m; i ++) printf("%d\n", (D[i]<<) % mod);
//system("pause");
return ;
}
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的输出数据中,第一个值是直流分量的振幅(这样对应周期有无穷的可能 ...
- 【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT
前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT.在网上找了很多这方面的资料做实验并进行 ...
- FFT
void FFT(complex a[],int n,int fl){ ,j=n/;i<n;i++){ if (i<j) {complex t=a[i];a[i]=a[j];a[j]=t; ...
随机推荐
- vs里根据json快速创建对应类的方法
有时候,我们在调用别人接口的时候,服务端返回了一个json格式的字符串,我们要获取json里面的数据的话一般有两种方式: 1.通过正则 2.反序列化成一个对象 第一种方式这里不再多说,主要说一下第二种 ...
- HttpClient (POST GET PUT)请求
HttpClient (POST GET PUT)请求 package com.curender.web.server.http; import java.io.IOException; import ...
- 序列化多个form表单内容同时提交
一.首先将表单主体序列化为json对象. 方法: //将表单序列化为json,这里加了个jQuery的扩展方法 $.fn.serializeJson = function () { var resul ...
- Mybatis 拦截器
Mybatis定义了四种拦截器: Executor (update, query, flushStatements, commit, rollback, getTransaction, close, ...
- jquery mobile
页面:data-role="page" header.content.fooder 过渡:data-transition ="slide" 反向过渡:dat ...
- Ruby字符串
在Ruby中的String对象持有和操纵的任意序列的一个或多个字节,通常表示人类语言的字符表示.简单的字符串文本括在单引号中,如 'This is a simple Ruby string liter ...
- MySQL Fabric和MyBatis的整合过程中遇到的问题
这是我昨天在整合MySQL Fabric和MyBatis时遇到的问题,花了大半天才解决的问题,解决的过程中在网上查找了很久,都没有找到解决的方案.现在记下来,希望能够帮助有同样问题的朋友.如果各位朋友 ...
- R3.2.2安装
- AJAX的核心XMLHttpRequest对象
为了实现异步通讯,提高用户体验度,而将很多旧知识(XML,DOM,JavaScript,HTML,jQuery,Css...)重新融合程一个新的知识框架.而XMLHttpRequest对象则是其中的重 ...
- 剑指Offer-【面试题02:实现Singleton 模式——七种实现方式】
题目:设计一个类,我们只能生成该类的一个实例 package com.cxz.demo02; /** * Created by CXZ on 2016/9/13. */ public class Si ...