首页 > 编程知识 正文

多项式除法例题100道,多项式除法

时间:2023-05-05 10:42:11 阅读:228490 作者:2900

Re.多项式除法/取模 前言

emmm又是暂无

前置

多项式求逆

 

多项式除法/取模目的

还是跟之前一样顾名思义】

给定一个多项式F(x),请求出多项式Q(x)和R(x),满足F(x)=Q(x)∗G(x)+R(x),R项数小于G,系数对998244353取模。

多项式除法/取模主要思路

先考虑一个多项式的反转操作

就是一个多项式系数前后调换

定义这个反转的操作下标加个 R

显然FR(x)=xnF(1/x)

接着推式子

F(x)=Q(x)∗G(x)+R(x)

F(1/x)=Q(1/x)∗G(1/x)+R(1/x)

xnF(1/x)=xn-mQ(1/x)∗xmG(1/x)+xm-1xn-m+1R(1/x)

FR(x)=QR(x)*GR(x)+xn-m+1RR(x)

所以当FR(x)=QR(x)*GR(x)+xn-m+1RR(x)(mod xn-m+1)

等于FR(x)=QR(x)*GR(x)(mod xn-m+1)

那么QR(x)=GR(x)*FR(x)-1(mod xn-m+1)

这时求出FR(x)在模xn-m+1即可求出QR(x)

反转回来就可得Q(x)

通过R(x)=F(x)-Q(x)∗G(x)

 

代码 #include<bits/stdc++.h>using namespace std;#define ll long long#define C getchar()-48inline ll read(){ ll s=0,r=1; char c=C; for(;c<0||c>9;c=C) if(c==-3) r=-1; for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c; return s*r;}const ll p=998244353,G=3,N=400010;ll n,m;ll f[N],g[N],q[N],r[N],inv[N],rev[N],c[N];ll tmp1[N],tmp2[N];inline ll ksm(ll a,ll b)//..快速幂 { ll ans=1; while(b) { if(b&1) ans=(ans*a)%p; a=(a*a)%p; b>>=1; } return ans;}inline void ntt(ll *a,ll n,ll kd)//ntt日常操作 { for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int i=1;i<n;i<<=1) { ll gn=ksm(G,(p-1)/(i<<1)); for(int j=0;j<n;j+=(i<<1)) { ll t1,t2,g=1; for(int k=0;k<i;k++,g=g*gn%p) { t1=a[j+k],t2=g*a[j+k+i]%p; a[j+k]=(t1+t2)%p,a[j+k+i]=(t1-t2+p)%p; } } } if(kd==1) return; ll ny=ksm(n,p-2); reverse(a+1,a+n); for(int i=0;i<n;i++) a[i]=a[i]*ny%p;}inline void cl(ll *a,ll *b,ll n,ll m,ll len,ll w)//处理 { for(int i=0;i<len;i++) tmp1[i]=i<n?a[i]:0;//复制 清空多余//因为tmp被使用多遍 而在做ntt时 用的是长度为len的 for(int i=0;i<len;i++) tmp2[i]=i<m?b[i]:0;//而有效的值只有它的得出的长度 后面其它的在模意义下都被清掉了 但之前在写的时候有的地方并没有清 //为了避免出错所以一定要清空 (在这个代码里)//..不要打成 i<n?tmp1[i]=a[i]:0;...只有像我这种蒟蒻才会犯这种错误吧 for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(w-1));//蝴蝶 }inline void polyinv(ll *a,ll *b,ll ed)//递推版 { b[0]=ksm(a[0],p-2);//设初始值 a*b=1(mod=x)b的值 for(int k=1,j=0;k<=(ed<<1);k<<=1,j++)//从两个长度为k的多项式a,b递推 {//!!因为这份代码的递推算的是 两个长度为a的多项式在模(zydlh)次下的逆元 //所以如果直接用ed为条件只会推出小于ed的逆元 所以ed要再乘一倍 ll len=k<<1; //len 两式子计算后大小 cl(a,b,k,k,len,j+1);//处理//j+1 要看len调整 因为len乘上了一倍 所以j在处理时也要加上1 之前没有加被坑了好久 ntt(tmp1,len,1);ntt(tmp2,len,1);//注意不要直接用a,b算 因为ntt后原多项式的值会变 为了方便所以先复制一遍在用复制的多项式算 for(int i=0;i<len;i++) b[i]=tmp2[i]*(2ll-tmp1[i]*tmp2[i]%p+p)%p;//求逆 ntt(b,len,-1); for(int i=k;i<len;i++) b[i]=0;//清空会被模的 //!!!不能删 因为下次递推是直接把0--len都作为有用的做下次运算了 }}inline void polymul(ll *a,ll *b,ll *c,ll n,ll m)//计算多项式相乘 { ll len=1,w=0; while(len<=(n+m)) len<<=1,w++; cl(a,b,n,m,len,w);//这里的次数(w)不用加1因为两者都是同不改变的 ntt(tmp1,len,1);ntt(tmp2,len,1); for(int i=0;i<len;i++) c[i]=tmp1[i]*tmp2[i]%p; ntt(c,len,-1);}inline void work() //f=q*g+r ask q,r f,g下标从0--n,0--m { reverse(f,f+1+n);//对应各式的反转操作 reverse(g,g+1+m); polyinv(g,inv,n-m+1);//求逆 因为反转后使r能够被忽略所以是在模x^(n-m+1)意义下的, 所以只要算出g在模x^(n-m+1)下的逆元 polymul(f,inv,q,n+1,n-m+1);//计算q reverse(q,q+n-m+1);//将原式反转回来 reverse(f,f+n+1); reverse(g,g+m+1); polymul(g,q,r,m+1,n-m+1);//计算q*g的值 for(int i=0;i<m;i++) r[i]=(f[i]-r[i]+p)%p;//相减算出r }int main(){ n=read(),m=read(); //读入 for(int i=0;i<=n;i++) f[i]=read(); for(int i=0;i<=m;i++) g[i]=read(); work(); for(int i=0;i<=n-m;i++) printf("%lld ",q[i]);printf("n");//输出 for(int i=0;i<m;i++) printf("%lld ",r[i]); return 0;} posted @ 2019-03-07 21:02 1436177712 阅读( ...) 评论( ...) 编辑 收藏

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。