打算写一个多项式总结。

虽然自己菜得太真实了。

好像四级标题太小了,下次写博客的时候再考虑一下。

模板

\(FFT\)模板

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL; inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
} const int MAXN=1000005;
const int MAXLEN=2100005;
const double pi=std::acos(-1);
int n,m;
int len,rev[MAXLEN];
struct Complex{
double real,imag;
inline friend Complex operator + (Complex x,Complex y){
return (Complex){x.real+y.real,x.imag+y.imag};
}
inline friend Complex operator - (Complex x,Complex y){
return (Complex){x.real-y.real,x.imag-y.imag};
}
inline friend Complex operator * (Complex x,Complex y){
return (Complex){x.real*y.real-x.imag*y.imag,x.real*y.imag+x.imag*y.real};
}
};
Complex A[MAXLEN],B[MAXLEN]; inline void fft(Complex *c,int dft){
rin(i,0,n-1) if(i<rev[i])
std::swap(c[i],c[rev[i]]);
for(int mid=1;mid<n;mid<<=1){
int r=(mid<<1);
Complex u=(Complex){std::cos(pi/mid),dft*std::sin(pi/mid)};
for(int l=0;l<n;l+=r){
Complex v=(Complex){1,0};
for(int i=0;i<mid;i++,v=v*u){
Complex x=c[l+i],y=c[l+mid+i]*v;
c[l+i]=x+y;
c[l+mid+i]=x-y;
}
}
}
if(dft<0) rin(i,0,n-1)
c[i].real/=n;
} int main(){
n=read(),m=read();
rin(i,0,n) A[i].real=read();
rin(i,0,m) B[i].real=read();
m+=n;
for(n=1;n<=m;n<<=1) len++;
rin(i,1,n-1) rev[i]=((rev[i>>1]>>1)|((i&1)<<(len-1)));
fft(A,1);
fft(B,1);
rin(i,0,n-1) A[i]=A[i]*B[i];
fft(A,-1);
rin(i,0,m) printf("%d ",(int)(A[i].real+0.5));
printf("\n");
return 0;
}

\(NTT\)模板

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL; inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
} const int MAXN=1000005;
const int MAXLEN=2100005;
const LL MOD=998244353,G=3,INVG=332748118;
int n,m,invn;
int len,rev[MAXLEN];
LL A[MAXLEN],B[MAXLEN]; inline LL qpow(LL x,LL y){
LL ret=1,tt=x%MOD;
while(y){
if(y&1) ret=ret*tt%MOD;
tt=tt*tt%MOD;
y>>=1;
}
return ret;
} inline void ntt(LL *c,int dft){
rin(i,0,n-1) if(i<rev[i])
std::swap(c[i],c[rev[i]]);
for(int mid=1;mid<n;mid<<=1){
int r=(mid<<1);
LL u=qpow(dft>0?G:INVG,(MOD-1)/r);
for(int l=0;l<n;l+=r){
LL v=1;
for(int i=0;i<mid;i++,v=v*u%MOD){
LL x=c[l+i],y=c[l+mid+i]*v%MOD;
c[l+i]=x+y;
if(c[l+i]>=MOD) c[l+i]-=MOD;
c[l+mid+i]=x-y;
if(c[l+mid+i]<0) c[l+mid+i]+=MOD;
}
}
}
if(dft<0) rin(i,0,n-1)
c[i]=c[i]*invn%MOD;
} int main(){
n=read(),m=read();
rin(i,0,n) A[i]=read();
rin(i,0,m) B[i]=read();
m+=n;
for(n=1;n<=m;n<<=1) len++;
rin(i,1,n-1) rev[i]=((rev[i>>1]>>1)|((i&1)<<(len-1)));
invn=qpow(n,MOD-2);
ntt(A,1);
ntt(B,1);
rin(i,0,n-1) A[i]=A[i]*B[i]%MOD;
ntt(A,-1);
rin(i,0,m) printf("%lld ",A[i]);
printf("\n");
return 0;
}

\(FWT\)模板

前方毒瘤码风警告!!!

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL; inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
} const int MAXN=135005;
const int MOD=998244353;
const int INV2=499122177;
int n;
int len;
int a[MAXN],b[MAXN];
int A[MAXN],B[MAXN],C[MAXN],D[MAXN]; inline void fwt(int *c,const char *s,int opt){
for(int mid=1;mid<n;mid<<=1){
int r=(mid<<1);
for(int l=0;l<n;l+=r){
for(int i=0;i<mid;i++){
if(s=="or"){
if(opt>0){
c[l+mid+i]+=c[l+i];
if(c[l+mid+i]>=MOD) c[l+mid+i]-=MOD;
}
else{
c[l+mid+i]-=c[l+i];
if(c[l+mid+i]<0) c[l+mid+i]+=MOD;
}
}
else if(s=="and"){
if(opt>0){
c[l+i]+=c[l+mid+i];
if(c[l+i]>=MOD) c[l+i]-=MOD;
}
else{
c[l+i]-=c[l+mid+i];
if(c[l+i]<0) c[l+i]+=MOD;
}
}
else{
LL x=c[l+i],y=c[l+mid+i];
c[l+i]=x+y;
c[l+mid+i]=x-y;
if(opt<0){
c[l+i]=1ll*c[l+i]*INV2%MOD;
c[l+mid+i]=1ll*c[l+mid+i]*INV2%MOD;
}
if(c[l+i]>=MOD) c[l+i]-=MOD;
if(c[l+mid+i]<0) c[l+mid+i]+=MOD;
}
}
}
}
} int main(){
len=read();
n=(1<<len);
rin(i,0,n-1) A[i]=B[i]=C[i]=a[i]=read();
rin(i,0,n-1) D[i]=b[i]=read();
fwt(A,"or",1);
fwt(D,"or",1);
rin(i,0,n-1) A[i]=1ll*A[i]*D[i]%MOD;
fwt(A,"or",-1);
rin(i,0,n-1) D[i]=b[i];
fwt(B,"and",1);
fwt(D,"and",1);
rin(i,0,n-1) B[i]=1ll*B[i]*D[i]%MOD;
fwt(B,"and",-1);
rin(i,0,n-1) D[i]=b[i];
fwt(C,"xor",1);
fwt(D,"xor",1);
rin(i,0,n-1) C[i]=1ll*C[i]*D[i]%MOD;
fwt(C,"xor",-1);
rin(i,0,n-1) printf("%d ",A[i]);
printf("\n");
rin(i,0,n-1) printf("%d ",B[i]);
printf("\n");
rin(i,0,n-1) printf("%d ",C[i]);
printf("\n");
return 0;
}

\(FFT/NTT/FWT\)的关键

找到在同一条件下的不变量,让其成为两个多项式卷积时下标的目标。

\(FFT/NTT\)习题

[BZOJ2179]FFT快速傅立叶

\(FFT\)优化高精乘,因为没有取模的问题所以可能在这里\(NTT\)的常数要优于\(FFT\)。

[BZOJ2194]快速傅立叶之二

将\(b\)数组\(reverse()\),发现原来的式子变成了:

\[C[k]=\sum(a[i] \times b[n+k-1-i])
\]

这是一个卷积的形式,\(FFT\)即可。

[BZOJ3527]力

博主之前的博客写过。链接

[BZOJ3160]万径人踪灭

我 卷 我 自 己

分别计算\(a\)和\(b\)对答案的贡献,然后\(Manacher\)减掉不合法的方案。

[BZOJ4503]两个串

[BZOJ2194]快速傅立叶之二出发,判断两个字符串是否匹配可以通过作差后平方转化为卷积的形式。由于通配符的存在外面还需要再乘一个\(T[i]\)。

[BZOJ4827][Hnoi2017]礼物

\(c\)的最优值一定为二次函数顶点,剩下的就是一个卷积了。

[HDU4609]3-idiots

先把生成函数搞出来,用\(FFT\)乘起来,把不合法的减去即可。

[BZOJ3625][Codeforces Round #250]小朋友和二叉树

跟据题意一波分析可得:

\[F(x) \equiv F(x)^2 \times G(x)+1\ (mod\ x^{m+1})
\]

\(G(x)\)是\(c\)的生成函数。

一元二次方程的求根公式搞上去,多项式开方加多项式求逆计算答案。

[BZOJ3509][CodeChef]COUNTARI

式子可以化为:

\[2 \times A[j]=A[i]+A[k]
\]

分块,块外\(FFT\),块内暴力即可。

[BZOJ3771]Triple

Something about 一般型生成函数里面讲过。

[UVA12633]Super Rooks on Chessboard

发现一条对角线可以用行标和列标的差表示,这令我们又想到了[BZOJ2194]快速傅立叶之二。可以将列标翻转,先只考虑棋子对整行和整列的影响,构造两个多项式,分别表示整行和整列的覆盖情况,如果一行或一列上没有棋子,那么对应多项式的相应次项的系数就是\(1\),否则是\(0\)。然后就可以\(FFT\)求出每条对角线上有几个没被覆盖的格子。最后考虑每条对角线是否对答案产生贡献即可。

[HDU5307]He is Flying

这道题有点神,博主一开始没想到什么靠谱的思路。

于是我们可以考虑上网搜题解。

题解告诉我们可以构造这样一个答案的生成函数:

\[F(x)=(\sum_{i=1}^nix^{sum_i}) \times (\sum_{i=1}^nx^{-sum_{i-1}})-(\sum_{i=1}^nx^{sum_i}) \times (\sum_{i=1}^n(i-1)x^{sum_{i-1}})
\]

特别的,需要单独计算\(s=0\)时的答案,\(O(n)\)扫一遍即可。

\(FWT\)习题

[HDU5909]Tree Cutting

\(F[i](x)\)表示以\(i\)为根的子树的生成函数,树形\(DP\),合并时使用\(FWT\)即可。

注意子图必须连通。

[BZOJ4589]Hard Nim

根据博弈论相关知识,\(NanoApe\)能获胜当且仅当所有堆石子异或和是负数。

搞出一堆石子的生成函数,然后\(FWT \Rightarrow QPOW \Rightarrow IFWT\)即可。

[CF662C]Binary Table

发现在变换的行一定时,所有列的初始状态和结束状态的\(xor\)一定(暂时不考虑列的变换)。\(G(x)\)统计每个初始状态的数量,\(H(x)\)表示每个结束状态的贡献,即\(H(x)\)的\(i\)次项系数\(h_i=min(\_\_builtin\_popcount(i),n-\_\_builtin\_popcount(i))\)。

\(F(x)=G(x) \oplus H(x)\),\(F(x)\)最小的系数即为答案。

[BZOJ4036][HAOI2015]按位或

根据\(min-max\)容斥,\(E(max\{S\})=\sum_{T \subseteq S}(-1)^{|T|+1}E(min\{T\})\)。

\(E(min\{T\})\)可以通过补集求,需要用到\(FWT\)。

随机推荐

  1. 【css】子元素浮动到了父元素外,父元素没有随子元素自适应高度,如何解决?

    正常情况 如果子元素没有设置浮动(float),父元素的高度会随着子元素高度的改变而改变的. 设置浮动以后 父元素的高度不会随着子元素的高度而变化. 例如:在一个ul中定义若干个li,并设置float ...

  2. python 并发编程 多进程 Process对象的其他属性方法 terminate与is_alive name pid 函数

    进程对象的其他方法一: terminate与is_alive is_alive()  立刻查看的子进程结果 是否存活 from multiprocessing import Process impor ...

  3. mysql定时任务/mysql作业

    转自:https://www.jb51.net/article/138569.htm 详细参考:https://www.cnblogs.com/qlqwjy/p/7954175.html(事件& ...

  4. 通过Spark Streaming处理交易数据

    Apache Spark 是加州大学伯克利分校的 AMPLabs 开发的开源分布式轻量级通用计算框架. 由于 Spark 基于内存设计,使得它拥有比 Hadoop 更高的性能(极端情况下可以达到 10 ...

  5. 给Repeater增加button事件,并绑定值

    ASPX页面: 增加两个事件,及传值. 1<asp:Repeater ID="rptList" OnItemDataBound="rptList_ItemDataB ...

  6. 如何获取图片的base64编码

    1.准备一张图片,比如1.gif 2.使用chrome浏览器,新建立一个窗口,然后将a.png拖动至浏览器窗口里面,打开控制台(检查),最后点击source 3.使用方法: 注意source获取的一串 ...

  7. oracle PL/SQL编程基础知识

    在oracle中使用pl/sql来扩展SQL的功能,使得SQL能够更加的灵活,功能更加强大,效率更高.pl/sql让sql也能执行判断,循环等操作.主要记录一下pl/sql的基本语法和基本条件判断语句 ...

  8. mac 命令行终端 设置代理

    环境: macOS Mojave 10.14.3 iTrem 2 3.2.8 酸酸乳1.1.4.4-R8 查看自己命令行的状态 curl ip.gs 正式开始 一.首先检查自己的酸酸乳是否正常,并在高 ...

  9. 简单的python笔试题

    1.输出九九乘法口诀 for i in range(1,10): for j in range(1,i+1): print('{}*{}={}'.format(j,i,i*j),end=' ') pr ...

  10. python打包命令

    打包成exe方法 (1)切换到该文件夹 (2)pyinstaller -F py文件 (py文件要英文才行) -F 生成单个可执行文件 -w 去掉控制台窗口 -p 自定义需要加载的类路径 -i 可执行 ...