• BZOJ3625


    此处不作题解。。只有细节

    记住两个多项式相乘的时候必须 在高位留出空,

    也就是代码里的memset(b+n,0,n<<2);

    然后 在%x^n的操作结束后一定要把>=n的部分清零,保持答案在%x^n意义下。(当然,如果能记得,之后用的时候再清零也行)

    还有就是从本题学到两个卡常技巧:

    一、

     1 ① Time:24732ms
     2 void ntt(int a[],int n,int d=1){
     3     for (int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
     4     for (int m=2;m<=n;m<<=1){
     5         int k=m>>1; LL wm=po(G,d*(mo-1)/m);
     6 
     7         for (int i=1;i<k;++i) w[i]=w[i-1]*wm%mo;    //瓶颈在这?
     8  
     9         for (int i=0;i<n;i+=m){
    10             for (int j=i;j<i+k;++j){
    11                 int u=a[j],v=1LL*w[j-i]*a[j+k]%mo;
    12                 a[j]=u+v<mo?u+v:u+v-mo;
    13                 a[j+k]=u<v?mo-v+u:u-v;
    14             }
    15         }
    16     }
    17     if (d==-1){
    18         LL x=po(n,mo-2);
    19         for (int i=0;i<n;++i) a[i]=x*a[i]%mo;
    20     }
    21 }
    22 
    23 ② Time:31844ms
    24 void ntt(int a[],int n,int d=1){
    25     for (int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
    26     for (int m=2;m<=n;m<<=1){
    27         int k=m>>1,wm=po(G,d*(mo-1)/m);
    28         for (int i=0;i<n;i+=m){
    29             LL w=1;
    30             for (int j=i;j<i+k;++j){
    31                 int u=a[j],v=w*a[j+k]%mo;
    32                 a[j]=u+v<mo?u+v:u+v-mo;
    33                 a[j+k]=u<v?mo-v+u:u-v;
    34                 w=w*wm%mo;
    35             }
    36         }
    37     }
    38     if (d==-1){
    39         LL x=po(n,mo-2);
    40         for (int i=0;i<n;++i) a[i]=x*a[i]%mo;
    41     }
    42 }
    卡卡

    二、

     1 ① Time:21844ms
     2 int w[N]; 
     3 int wm=po(G,d*(mo-1)/m);
     4 for (int i=1;i<k;++i) w[i]=1LL*w[i-1]*wm%mo;
     5 
     6 ② Time:24732ms    所以瓶颈应该是LL的读写速度(吧。。。)
     7 LL w[N];
     8 LL wm=po(G,d*(mo-1)/m);
     9 for (int i=1;i<k;++i) w[i]=w[i-1]*wm%mo;
    10 
    11 ③ Time:24696ms    这个是为了证明并不是LL*LL和LL*int的瓶颈
    12 LL w[N];
    13 int wm=po(G,d*(mo-1)/m);
    14 for (int i=1;i<k;++i) w[i]=w[i-1]*wm%mo;
    常数

    贴代码

     1 #include <bits/stdc++.h>
     2 #define LL long long
     3 using namespace std;
     4 const int mo=998244353;
     5 const int G=3;
     6 const int N=300000;
     7 int n,m,rev[N],x,b[N],c[N],t1[N],t2[N],t3[N],w[N];
     8 int po(int x,int y){
     9     if (y<0) y=y%(mo-1)+mo-1; int z=1;
    10     for(;y;y>>=1,x=1LL*x*x%mo) if (y&1) z=1LL*z*x%mo;
    11     return z;
    12 }
    13 void ntt(int a[],int n,int d=1){
    14     for (int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
    15     for (int m=2;m<=n;m<<=1){
    16         int k=m>>1,wm=po(G,d*(mo-1)/m);
    17         for (int i=1;i<k;++i) w[i]=1LL*w[i-1]*wm%mo;
    18         for (int i=0;i<n;i+=m){
    19             for (int j=i;j<i+k;++j){
    20                 int u=a[j],v=1LL*w[j-i]*a[j+k]%mo;
    21                 a[j]=u+v<mo?u+v:u+v-mo;
    22                 a[j+k]=u<v?mo-v+u:u-v;
    23             }
    24         }
    25     }
    26     if (d==-1){
    27         LL x=po(n,mo-2);
    28         for (int i=0;i<n;++i) a[i]=x*a[i]%mo;
    29     }
    30 }
    31 void inv(int *a,int n,int *b){
    32     if (n==1){
    33         b[0]=po(a[0],mo-2);
    34         b[1]=0; return;
    35     }
    36     inv(a,n>>1,b); int m=n<<1;
    37     for (int i=0;i<n;++i) t3[i]=a[i];
    38     memset(b+n,0,n<<2); memset(t3+n,0,n<<2);
    39     for (int i=0;i<m;++i) rev[i]=(rev[i>>1]>>1)+(i&1)*(m>>1);
    40     ntt(t3,m); ntt(b,m);
    41     for (int i=0;i<m;++i) b[i]=(2LL+mo-1LL*t3[i]*b[i]%mo)*b[i]%mo;
    42     ntt(b,m,-1);
    43     memset(b+n,0,n<<2);
    44 }
    45 void gen(int *a,int n,int *b){
    46     if (n==1){
    47         b[0]=1; b[1]=0; return;
    48     }
    49     gen(a,n>>1,b); int m=n<<1;
    50     for (int i=0;i<n;++i) t1[i]=a[i];            
    51     memset(t1+n,0,n<<2);
    52     inv(b,n,t2);
    53     for (int i=0;i<m;++i) rev[i]=(rev[i>>1]>>1)+(i&1)*(m>>1);
    54     ntt(t1,m); ntt(t2,m);
    55     for (int i=0;i<m;++i) t1[i]=1LL*t1[i]*t2[i]%mo;
    56     ntt(t1,m,-1); LL x=mo+1>>1;
    57     for (int i=0;i<n;++i) b[i]=x*(b[i]+t1[i])%mo;
    58     memset(b+n,0,n<<2);
    59 }
    60 int main(){
    61     scanf("%d%d",&n,&m);
    62     for (int i=1;i<=n;++i){
    63         scanf("%d",&x);
    64         if (x<=m) c[x]=mo-4;
    65     }
    66     n=1; w[0]=1;
    67     while (n<=m) n<<=1;
    68     c[0]=1; gen(c,n,b);
    69     if (b[0]) (++b[0])%=mo;
    70     else{
    71         for (int i=0;i<n;++i) b[i]=mo-b[i];
    72         b[0]?--b[0]:b[0]=mo-1;
    73     }
    74     inv(b,n,c);
    75     for (int i=1;i<=m;++i) printf("%d
    ",(c[i]<<1)%mo);
    76     return 0;
    77 }
    Final
  • 相关阅读:
    盛最多水的容器
    寻找2个有序数组的中位数
    从链表中删除总和值为0的连续节点
    链表中的下一个更大节点
    链表的中间节点
    循环有序链表的插入
    设计链表
    链表组件
    扁平化多级双向链表
    将二叉搜索数转化为排序的双向链表
  • 原文地址:https://www.cnblogs.com/cyz666/p/6918684.html
Copyright © 2020-2023  润新知