ntt

【洛谷P5158】 【模板】多项式快速插值

我只是一个虾纸丫 提交于 2019-12-05 14:41:28
卡常严重,可有采用如下优化方案: 1.预处理单位根 2.少取几次模 3.复制数组时用 memcpy 4.进行多项式乘法项数少的时候直接暴力乘 5.进行多项式多点求值时如果项数小于500的话直接秦九昭展开 code: #include <bits/stdc++.h> #define ll long long #define ull unsigned long long #define setIO(s) freopen(s".in","r",stdin) // , freopen(s".out","w",stdout) using namespace std; char buf[100000],*p1,*p2; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() { int x=0; char s=nc(); while(s<'0') s=nc(); while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc(); return x; } void print(int x) {if(x>=10) print(x/10);putchar(x%10+'0');} const int G=3; const int N=2000005;

Berlekamp-Massey算法

只愿长相守 提交于 2019-12-05 08:58:47
\(BM\) 算法可以在 \(O(n^2)\) 的时间里用来求出一个长度为 \(n\) 的数列的最短递推式 用处是在题目中打出小范围的表之后求出递推式并配合CH定理来求出最终的答案 以下无特殊说明时均默认下标从 \(1\) 开始,用 \(|B|\) 表示数列 \(B\) 的长度 算法流程 对于某个长为 \(n\) 的数列 \(\{a_i\}\) ,我们称某个长为 \(m\) 的数列 \(\{b_i\}\) 为其递推式,当且仅当对于任意 \(m+1\leq i\leq n\) ,有 \(a_i=\sum\limits_{j=1}^m b_ja_{i-j}\) 恒成立。称 \(\{b_i\}\) 为其最短线性递推式当且仅当 \(m\) 是所有递推式中最小的。注意, \(m\geq n\) 的情况也是允许的,此时由于不存在 \(m+1\leq i\leq n\) ,所以此时必定是 \(a\) 的线性递推式 我们考虑增量法,设当前已经求出了 \(a_{1,...,i-1}\) 的最短线性递推式,考虑加入 \(a_i\) 之后的最短线性递推式 记初始时的递推式为 \(B_0=\varnothing\) ,假设递推式被修改了 \(k\) 次,且第 \(i\) 次修改后的递推式为 \(B_i\) ,那么当前的线性递推式就是 \(B_k\) 设当前递推式为 \(B_k\) ,记 \(d_i=a_i

「学习笔记」FFT及NTT入门知识

孤街浪徒 提交于 2019-12-03 10:54:59
前言 快速傅里叶变换( \(\text{Fast Fourier Transform,FFT}\) )是一种能在 \(O(n \log n)\) 的时间内完成多项式乘法的算法,在 \(OI\) 中的应用很多,是多项式相关内容的基础。下面从头开始介绍 \(\text{FFT}\) 。 前置技能:弧度制、三角函数、平面向量。 多项式 形如 \(f(x)=a_0+a_1x+a_2x^2+...+a_nx^n\) 的式子称为 \(x\) 的 \(n\) 次多项式。其中 \(a_0,a_1,...,a_n\) 称为多项式的系数。 系数表达法 上面定义中的表示就是系数表达法。其系数可看成 \(n+1\) 维向量 \(\vec a=(a_0,a_1,...,a_n)\) 。 点值表达法 把多项式看成一个函数,点值表示就用它图像上的 \(n+1\) 个不同的点 \((x_0,y_0),...,(x_n,y_n)\) 来确定这个多项式。多项式有不止一个点值表示,可以证明每个点值表示确定唯一的系数表达多项式。 复数 虚数单位 \(i\) 被称为虚数单位。规定 \(i=\sqrt {-1}\) 。 复平面 复数的平面由 \(x,y\) 轴组成。 \(x\) 轴称为实轴, \(y\) 轴称为虚轴。平面内的每一个从原点到某个点 \((a,b)\) 的向量 \(\vec a=(a,b)\) 表示复数 \(a

NTT注意事项

匿名 (未验证) 提交于 2019-12-03 00:38:01
记住几个常用的素数及原根: 998244353==>3 1004535809==>3 167772161==>3 参考这里: https://www.cnblogs.com/Guess2/p/8422205.html 贴代码,看细节: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=3e6+10; const long long mod=1004535809;//注意模数 int n,m; long long a[maxn],b[maxn]; inline long long Pow(long long x,long long b) { long long res=1; for(;b;b>>=1) { if(b&1) res=res*x%mod; x=x*x%mod; } return res; } namespace TNT { long long p[maxn],w[21]; int n,m; inline void init(int len) { for(n=1,m=0;n<=len;n<<=1,m++);//注意是n<=len等于号不能丢 for(int i=1;i<n;i++) p[i]=(p

[2018.6.22集训]admirable-拆系数FFT-多项式相关

匿名 (未验证) 提交于 2019-12-03 00:32:02
给出一棵树,现在需要将$k$条不相同的路径覆盖到这棵树上。 定义一种合法的路径覆盖方案为,能使得树上的每条边的被覆盖次数$t \in {0,1,k}$的方案。 求合法方案的数量,对$10^9 +9$取模。 $n,k \leq 10^5$。 很容易想到一个计算答案的方法: 被覆盖$k$次的部分一定是一条链,枚举这条链,并对每条枚举的链,计算可行的方案数并累加。 对于每条覆盖$k$次的链,可以发现,如果分别计算出两个端点处的方案,将其贡献乘起来,即可得到这条链的方案数。 可以发现,对于一个端点处的合法方案,每一条路径在这一侧的端点均在这条链的端点的不同子树中或恰好在这个端点上,因为若有两条路径在同一子树中,会经过同一条边多次,方案会不合法。 考虑如何计算这个方案数,可以使用多项式乘法解决,构造形如$size[v]*x+1$的多项式,并将每个子树的多项式乘起来,再取出前$k$项的系数,采用全排列和组合数计算贡献。 因此,每个点所$u$需要的多项式,为$\prod\limits_{(u,v) \in E}size[v]*x+1$,除掉与当前枚举的链相交的一侧的儿子的多项式得到。 乘或除掉一个二项式是$O(n)$的,同时如果预处理,乘除操作的次数将为$O(n)$,因此预处理一个节点处的多项式再枚举,复杂度$O(n^2)$。 考虑优化。 对于计算初始每个节点处所有儿子乘起来得到的多项式

NTT

匿名 (未验证) 提交于 2019-12-02 23:59:01
namespace NTT { const int g = 3; int power(int x, int t) { int ret = 1; for(; t; t >>= 1, x = 1LL * x * x % P) if(t & 1) ret = 1LL * ret * x % P; return ret; } void NTT(int *a, int len, int f) { int n = 1 << len; for(int i = 0; i < n; ++i) { int t = 0; for(int j = 0; j < len; ++j) if(i >> j & 1) t |= 1 << (len - j - 1); if(i < t) swap(a[i], a[t]); } for(int l = 2; l <= n; l <<= 1) { int m = l >> 1; int w = power(g, f == 1 ? (P - 1) / l : (P - 1) - (P - 1) / l); for(int i = 0; i < n; i += l) { int t = 1; for(int k = 0; k < m; ++k, t = 1LL * t * w % P) { int x = a[i + k], y = 1LL * t * a[i + m +

HDU多校训练第一场 1012 Sequence

匿名 (未验证) 提交于 2019-12-02 23:49:02
题目链接:acm.hdu.edu.cn/showproblem.php?pid=6589 题意:给出一个长度为n的数组,有m次操作,操作有3种1,2,3,问操作m次后的数组,输出i*a[i]的异或和 操作k的实质是进行一次O(n)的计算,a[i]+=a[i-k] (i-k>0) k=1时,我们可以发现这是一次求前缀和的操作 k=2时,我们可以发现这是对于1,3,5,7... 2,4,6,8...两个子数组分别进行求前缀和的操作 k=3时,我们可以发现这是对于1,4,7,11...2,5,8,12...3,6,9,12...三个子数组分别求前缀和的操作 暴力的复杂度是O(mn),我们可以模拟出暴力的过程,其实这并不是一个浪费时间的过程,因为在比赛时,我们通过这个暴力的程序验算样例,发现了一个性质,那就是操作顺序的改变,并不会影响结果! 这个性质是解题的关键,如果没有发现这个性质,那么是想不到正解的,那么,问题的本质就变成了如何快速求出m次前缀和,粗略一想很显然这还是个o(nm)的操作,其实不然 观察求前缀和的过程 0次(不求):a[1],a[2],a[3],a[4],a[5]... ... 这里,规律就很明显了,我们可以发现进行多次前缀和后的数组,它的结果是和组合数有关的 第m次,组合数数组应该是c[i]=C(m+i-2,i-1),那么,上述结果用数组表示就是 这个东西已经很明显了

CF 848E(动态规划+分治NTT)

匿名 (未验证) 提交于 2019-12-02 23:47:01
http://codeforces.com/problemset/problem/848/E 假设0-n一定有一条边,我们得到了一个方案,那么显然是可以旋转得到其他方案的。 记最大的i满足i到i+n有一条边,那么旋转的方案数是n-i 考虑动态规划: 设 \(g[i]\) 表示i个点,只用相邻或隔一个去拼接的方案数。 转移显然有 \(g[i]=g[i-2]+g[i-4]\) 。 设 \(f[i][0/1][0/1]\) 表示1有连对面的,n+1有连对面的,2-n填,前面后面是否要伸出去的方案数。 那么显然有 \(f[i][j][k]=g[i-1-j-k]*(i-1)^2\) 。 设 \(h[i][0/1]\) 表示前i个确定了,第i个是连对面,后面是否伸出去。 显然有 \(h[i][v]=\sum_{j=0}^{i-1}h[j][u]*f[i-j][u][v]\) 初值为: \(h[0][0]=1->ans+=?*h[?][0]\) \(h[0][1]=1->ans+=?*h[?][1]\) 由于最后一段有长度的额外贡献,所以: \(Ans=\sum_{i=0}^{n-1}h[i][u]*f[n-i][u][?]*(n-i)\) 这个东西显然可以分治NTT优化转移。 Code: #include<bits/stdc++.h> #define fo(i, x, y) for(int i

【题解】数字组合(NTT+组合 滑稽)

匿名 (未验证) 提交于 2019-12-02 23:41:02
今天实践一下谢总讲的宰牛刀233,滑稽。 \((1+x)(1+x)(1+x)\) 的 \(x^2\) 系数就代表了有三个一快钱硬币构成的两块钱的方案数量。 很好理解,毕竟拆括号这种东西本身就有组合意义。 那么假设面值 \(i\) 有 \(a_i\) 个,那么最终的答案是 \[ G(x)=\prod_{i=1}^{1000} (1+{a_i\choose 1}x+{a_i\choose 2}x^2\dots) \] 的 \(x^m\) 项系数 直接NTT即可。 //@winlere #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; inline int qr(){ register int ret=0,f=0; register char c=getchar(); while(c<48||c>57)f|=c==45,c=getchar(); while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar(); return f?-ret:ret; } int la,lb; const int maxn=1<<17|1; int a[maxn],b[maxn]; const

NTT 模板

ぐ巨炮叔叔 提交于 2019-12-02 22:07:42
其实和 \(FFT\) 就是一个模子里刻出来的一样, \(FFT\) 的优化是基于它的单位根 而 \(NTT\) 的模数通常有一个原根, 和 \(FFT\) 的单位根有类似的性质 还是存个模板 #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXN 3000010 using namespace std; typedef long long LL; const int mod=998244353; const int g=3; int n,m,rev[MAXN],bit=0,len=1; LL a[MAXN],b[MAXN]; int read(){ int x=0,f=1;char c=getchar(); while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();} return x*f; } LL qpow(LL x,LL k){ LL res=1; while(k){ if(k&1) res=res*x%mod; x=x*x%mod; k>>=1; } return res; } void NTT(LL *a