JZYZOJ 2042 多项式逆元 NTT 多项式

http://172.20.6.3/Problem_Show.asp?id=2042

题意:求一个次数界为n的多项式在模P并模x^m的意义下的逆元。P=7*17*2^23+1。

多项式逆元的含义以及求逆元的方法:http://blog.miskcoo.com/2015/05/polynomial-inverse

公式推导一下。主要还是NTT的使用,我NTT写错了调了半天,太zz了。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<complex>
 7 using namespace std;
 8 #define LL long long
 9 const LL P=(LL)7*17*(1<<23)+1;
10 const int maxn=530010;
11 LL a[maxn]={},b[maxn]={},e[maxn]={},zz[20][maxn]={};
12 int bel[maxn]={};
13 int bt,s,tot=0;
14 LL mpow(LL x,LL k){
15     if(k<0){x=mpow(x,P-2);k=-k;}
16     LL z=1;
17     while(k){
18         if(k&1)z=(z*x)%P;
19         x=(x*x)%P;
20         k/=2;
21     }return z;
22 }
23 inline void getit(){ for(int i=0;i<s;i++)bel[i]=((bel[i>>1]>>1)|((i&1)<<(bt-1))); }
24 inline void ntt(LL *c,int n,int dft){
25     for(int i=0;i<n;i++)if(bel[i]>i)swap(c[bel[i]],c[i]);
26     for(int step=1;step<n;step<<=1){
27         LL w=mpow(3,((P-1)/(step*2))*dft);
28         for(int j=0;j<n;j+=(step<<1)){
29             LL z=1;
30             for(int i=j;i<j+step;++i){
31                 LL x=c[i],y=(c[i+step]*z)%P;
32                 c[i]=(x+y)%P;
33                 c[i+step]=((x-y)%P+P)%P;
34                 z=(z*w)%P;
35             }
36         }
37     }
38     if(dft==-1){
39         LL mon=mpow(n,P-2);
40         for(int i=0;i<n;i++)c[i]=(c[i]*mon)%P;
41     }
42 }
43 inline void dontt(LL *c,LL *d,int x,int y){
44     bt=1;s=2;int z=x+y-1;
45     for(;s<z;++bt)s<<=1;
46     getit();
47     ntt(c,s,1);ntt(d,s,1);
48     for(int i=0;i<s;i++)c[i]=(c[i]*d[i])%P;
49     ntt(c,s,-1);ntt(d,s,1);
50 }
51 inline void doit(int n,int m){
52     if(m==1){++tot; zz[tot][0]=mpow(a[0],P-2); return ;}
53     doit(n,(m+1)/2);int siz=(m+1)/2; ++tot;
54     for(int i=0;i<s;i++)e[i]=b[i]=bel[i]=0;
55     for(int i=0;i<siz;i++){zz[tot][i]=(zz[tot-1][i]*2)%P;b[i]=zz[tot-1][i];}
56     for(int i=min(n,m)-1;i>=0;--i)e[i]=a[i];
57     dontt(zz[tot-1],b,siz,siz); siz=siz+siz-1;
58     dontt(zz[tot-1],e,siz,min(n,m));
59     for(int i=0;i<m;i++)zz[tot][i]=((zz[tot][i]-zz[tot-1][i])%P+P)%P;
60 }
61 int main(){
62     //freopen("a.in","r",stdin);
63     int n,m;scanf("%d%d",&n,&m);
64     for(int i=0;i<n;i++){scanf("%lld",&a[i]);a[i]=((a[i]%P)+P)%P;}
65     doit(n,m);
66     for(int i=0;i<m;i++)printf("%lld ",zz[tot][i]);
67     printf("\n");
68     return 0;
69 }
View Code

 

转载于:https://www.cnblogs.com/137shoebills/p/9164339.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值