luogu P4512 多项式除法 (模板题、FFT、多项式求逆)
手动博客搬家: 本文发表于20181206 14:42:53, 原地址https://blog.csdn.net/suncongbo/article/details/84853342
题目链接: https://www.luogu.org/problemnew/show/P4512
没想到这算法这么蠢。。一点都不难啊。。我连这都推不出来我是不是没救了
这个多项式满足\(A(x)=B(x)Q(x)+R(x)\), 如果已知\(R(x)\)是\(0\), 那显然很好处理,求个逆就行了。
那如果有余数呢?很简单,如果我们把这个多项式的系数翻转(reverse),那么\(R(x)\)就从低次项变成了高次项,低次项就不再受\(R(x)\)的而影响了。
这是我们的基本思路。下面我们来形式化这个过程:
\(A(x)=B(x)Q(x)+R(x)\)
对于\(n\)次多项式\(F(x)\)令\(F_R(x)=x^nF(\frac{1}{x})\) (这就是前面所说的reverse操作)
则有\(x^nA(\frac{1}{x})=x^mB(\frac{1}{x})x^{n-m}Q(\frac{1}{x})+x^{m-1}R(\frac{1}{x})x^{n-m+1}\)
\(A_R(x)=B_R(x)Q_R(x)+x^{n-m+1}R_R(x)\)
\(A_R(x)\equiv B_R(x)Q_R(x) (\mod x^{n-m+1})\)
于是我们求\(B_R(x)\)在\(\mod x^{n-m+1}\)意义下的逆,然后乘以\(A_R(x)\)即可求出\(Q_R(x)\), 从而得到\(Q(x)\).
然后用\(R(x)=A(x)-B(x)Q(x)\)即可求出\(R(x)\).
(虽然算法简单但是要注意的地方还挺多……容易错。)
时间复杂度\(O(n\log n)\), 我写的进行了\(24\)倍常数的ntt.
空间复杂度\(O(n)\), 我的实现好像需要开\(8\)倍。
代码实现
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define llong long long
#define modinc(x) {if(x>=P) x-=P;}
using namespace std;
const int N = 1<<19;
const int LGN = 19;
const llong G = 3ll;
const int P = 998244353;
llong tmp1[N+3],tmp2[N+3],tmp3[N+3],tmp4[N+3];
llong tmp5[N+3],tmp6[N+3],tmp7[N+3],tmp8[N+3],tmp9[N+3];
llong a[N+3],b[N+3],q[N+3],r[N+3];
int id[N+3];
int n,m;
llong quickpow(llong x,llong y)
{
llong cur = x,ret = 1ll;
for(int i=0; y; i++)
{
if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
cur = cur*cur%P;
}
return ret;
}
llong mulinv(llong x) {return quickpow(x,P-2)%P;}
void initid(int dgr)
{
int len = 0; for(int i=0; i<=LGN; i++) if((1<<i)==dgr) {len = i; break;}
id[0] = 0;
for(int i=1; i<dgr; i++) id[i] = (id[i>>1]>>1)|(i&1)<<(len-1);
}
int getdgr(int x)
{
int ret = 1;
while(ret<=x) ret<<=1;
return ret;
}
void ntt(int dgr,int coe,llong poly[],llong ret[])
{
initid(dgr);
for(int i=0; i<dgr; i++) ret[i] = poly[i];
for(int i=0; i<dgr; i++) if(i<id[i]) swap(ret[i],ret[id[i]]);
for(int i=1; i<=(dgr>>1); i<<=1)
{
llong tmp = quickpow(G,(P-1)/(i<<1));
if(coe==-1) tmp = mulinv(tmp);
for(int j=0; j<dgr; j+=(i<<1))
{
llong expn = 1ll;
for(int k=0; k<i; k++)
{
llong x = ret[j+k],y = ret[j+i+k]*expn%P;
ret[j+k] = x+y; modinc(ret[j+k]);
ret[j+i+k] = x-y+P; modinc(ret[j+i+k]);
expn = (expn*tmp)%P;
}
}
}
if(coe==-1)
{
llong tmp = mulinv(dgr);
for(int j=0; j<dgr; j++) ret[j] = ret[j]*tmp%P;
}
}
void polyinv(int dgr,llong poly[],llong ret[])
{
for(int i=0; i<dgr; i++) ret[i] = 0ll;
ret[0] = mulinv(poly[0]);
for(int i=1; i<=(dgr>>1); i<<=1)
{
for(int j=0; j<(i<<2); j++) tmp1[j] = j<i ? ret[j] : 0ll;
for(int j=0; j<(i<<2); j++) tmp2[j] = j<(i<<1) ? poly[j] : 0ll;
ntt((i<<2),1,tmp1,tmp3); ntt((i<<2),1,tmp2,tmp4);
for(int j=0; j<(i<<2); j++) tmp3[j] = tmp3[j]*tmp3[j]%P*tmp4[j]%P;
ntt((i<<2),-1,tmp3,tmp4);
for(int j=0; j<(i<<1); j++) ret[j] = (tmp1[j]+tmp1[j]-tmp4[j]+P)%P;
}
for(int j=dgr; j<(dgr<<1); j++) ret[j] = 0ll;
}
void polyrev(int dgr,llong poly[],llong ret[])
{
for(int i=0; i<dgr; i++) ret[i] = poly[dgr-1-i];
}
void polydiv(int dgr1,int dgr2,llong poly1[],llong poly2[],llong ret1[],llong ret2[])
{
int _dgr1 = getdgr(dgr1),_dgr2 = getdgr(dgr2);
polyrev(dgr2,poly2,tmp5); polyrev(dgr1,poly1,tmp9);
polyinv(_dgr1,tmp5,tmp6);
for(int i=dgr1-dgr2+1; i<(_dgr1<<1); i++) tmp6[i] = 0ll;
ntt(_dgr1<<1,1,tmp9,tmp7); ntt(_dgr1<<1,1,tmp6,tmp8);
for(int i=0; i<(_dgr1<<1); i++) tmp7[i] = tmp7[i]*tmp8[i]%P;
ntt(_dgr1<<1,-1,tmp7,tmp8);
for(int i=dgr1-dgr2+1; i<(_dgr1<<1); i++) tmp8[i] = 0ll;
polyrev(dgr1-dgr2+1,tmp8,ret1);
ntt(_dgr1<<1,1,poly2,tmp7); ntt(_dgr1<<1,1,ret1,tmp8);
for(int i=0; i<(_dgr1<<1); i++) tmp7[i] = tmp7[i]*tmp8[i]%P;
ntt(_dgr1<<1,-1,tmp7,ret2);
for(int i=dgr2; i<(_dgr1<<1); i++) ret2[i] = 0ll;
for(int i=0; i<dgr2-1; i++) ret2[i] = (poly1[i]-ret2[i]+P)%P;
}
int main()
{
scanf("%d%d",&n,&m); n++; m++;
for(int i=0; i<n; i++) scanf("%lld",&a[i]);
for(int i=0; i<m; i++) scanf("%lld",&b[i]);
int dgr1 = getdgr(n),dgr2 = getdgr(m);
polydiv(n,m,a,b,q,r);
for(int i=0; i<=n-m; i++) printf("%lld ",q[i]); puts("");
for(int i=0; i<m-1; i++) printf("%lld ",r[i]);
return 0;
}
luogu P4512 多项式除法 (模板题、FFT、多项式求逆)的更多相关文章
- luogu P4726 多项式指数函数(模板题FFT、多项式求逆、多项式对数函数)
手动博客搬家: 本文发表于20181127 08:39:42, 原地址https://blog.csdn.net/suncongbo/article/details/84559818 题目链接: ht ...
- luogu P4725 多项式对数函数 (模板题、FFT、多项式求逆、求导和积分)
手动博客搬家: 本文发表于20181125 13:25:03, 原地址https://blog.csdn.net/suncongbo/article/details/84487306 题目链接: ht ...
- UVA 796 Critical Links(模板题)(无向图求桥)
<题目链接> 题目大意: 无向连通图求桥,并将桥按顺序输出. 解题分析: 无向图求桥的模板题,下面用了kuangbin的模板. #include <cstdio> #inclu ...
- UVA 315 Network (模板题)(无向图求割点)
<题目链接> 题目大意: 给出一个无向图,求出其中的割点数量. 解题分析: 无向图求割点模板题. 一个顶点u是割点,当且仅当满足 (1) u为树根,且u有多于一个子树. (2) u不为树根 ...
- 2014 HDU多校弟五场A题 【归并排序求逆序对】
这题是2Y,第一次WA贡献给了没有long long 的答案QAQ 题意不难理解,解题方法不难. 先用归并排序求出原串中逆序对的个数然后拿来减去k即可,如果答案小于0,则取0 学习了归并排序求逆序对的 ...
- 线段树菜鸟一题+归并排序【求逆序数】POJ2299
题目链接:http://poj.org/problem?id=2299 归并排序解法链接:http://blog.csdn.net/lyy289065406/article/details/66473 ...
- [洛谷P4721]【模板】分治 FFT_求逆
题目大意:给定长度为$n-1$的数组$g_{[1,n)}$,求$f_{[0,n)}$,要求: $$f_i=\sum_{j=1}^if_{i-j}g_j\\f_0=1$$ 题解:分治$FFT$博客,发现 ...
- 【luogu P3803】【模板】多项式乘法(FFT)
[模板]多项式乘法(FFT) 题目链接:luogu P3803 题目大意 给你两个多项式,要你求这两个多项式乘起来得到的多项式.(卷积) 思路 系数表示法 就是我们一般来表示一个多项式的方法: \(A ...
- P4512 【模板】多项式除法
思路 多项式除法板子 多项式除法 给出\(A(x)\)和\(B(x)\),求一个\(n-m\)次的多项式\(D(x)\),一个\(m-1\)次多项式\(R(x)\),满足 \[ A(x)=B(x)D( ...
随机推荐
- git 的安装和使用
安装Git 下载并安装 mysysgit 下载并安装 git windows版本号 配置Git 设置你的名字和邮箱 git config --global user.name "xxxx&q ...
- 每日总结-05-19(AC自己主动机结束)
今天下午讨论了一下校赛的题,最终最终拍板,把校赛的题目定下来了. 然后今天A掉了4个AC自己主动机的题目.最终完毕了AC自己主动机专辑里面的15个题.至此AC自己主动机全然结束. 明天开启线段树专题. ...
- IOS 京东相关app 出现“网络请求失败,请检查您的网络设置”的解决办法
问题情况 在IOS系统下,下载安装或者更新新版的京东相关app之后,打开app直接就是“网络请求失败,请检查网络设置”,无论是数据连接还是wifi都试了,都是网络请求失败. 然而打开无线局域网-使用无 ...
- splay树入门(带3个例题)
splay树入门(带3个例题) 首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. PS:若代码有误,请尽快与本人联系,我会尽快改正 首先引入一下splay的概念,他的中文名 ...
- codeforces 915D Almost Acyclic Graph 拓扑排序
大意:给出一个有向图,问能否在只去掉一条边的情况下破掉所有的环 解析:最直接的是枚举每个边,将其禁用,然后在图中找环,如果可以就YES,都不行就NO 复杂度O(N*M)看起来不超时 但是实现了以后发现 ...
- Device /dev/sdb1 not found (or ignored by filtering)
/etc/lvm/lvm.conf filters
- 排序系列 之 堆排序算法 —— Java实现
基本概念: 二叉堆是完全二叉树或者是近似完全二叉树. 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆. 一般将二叉堆简称 ...
- E20170816-mk
deque 即双端队列.是一种具有队列和栈的性质的数据结构. revert vi. 恢复; 重提; 回到…上; <律>归还; n. 归属; 恢复原来信仰的人; Indicator ...
- [Apple开发者帐户帮助]二、管理你的团队(4)离开一个团队
您可以随时离开组织的开发团队.但是,帐户持有人有法律责任,只能在指定另一个团队成员作为帐户持有人后离开团队. 如果您是Apple Developer Program中的团队成员,则可以将团队留在App ...
- Appium + python - 监控appium server start
import osimport time as t def start_appium(port = 4723,udid="4871660c"): a = os.popen(&quo ...