zoukankan      html  css  js  c++  java
  • LOJ #556. 「Antileaf's Round」咱们去烧菜吧

    好久没更博了

    咕咕咕

    现在多项式板子的常数巨大...周末好好卡波常吧....

    LOJ #556


    题意

    给定$ m$种物品的出现次数$ B_i$以及大小$ A_i$

    求装满大小为$[1..n]$的背包的方案数各是多少

    数据范围全是$ 10^5$


    $ Solution$

    转化成生成函数求解

    即是要求

    $Ans=prodlimits_{i=1}^m sumlimits_{j=0}^{B_i} x^{A_i·j}$

    等比数列收敛一下即是

    $Ans= prodlimits_{i=1}^m frac{1-x^{(B_i+1)·A_i}}{1-x^{A_i}}$

    直接乘复杂度巨大,考虑转求$ Ln(Ans)$

    则有

    $Ans=Exp(sumlimits_{i=1}^m Ln(1-x^{(B_i+1)·A_i})-Ln(1-x^{A_i}))$

    其中$ Ln(1-x)$的泰勒级数为$-sumlimits_{i=1}^{infty}frac{x^i}{i}$

    开个桶对所有指数记录一下,读入完成后调和级数累加即可

    然后就是多项式$ Exp$的模版了

    时间复杂度$ O(n log n)$


    $ my code$ 

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define rt register int
    #define ll long long
    using namespace std;
    namespace fast_IO{
        const int IN_LEN=10000000,OUT_LEN=10000000;
        char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
        inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
        inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
        inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
    }
    using namespace fast_IO;
    //#define getchar() getchar_()
    //#define putchar(x) putchar_((x))
    inline ll read(){
        ll x=0;char zf=1;char ch=getchar();
        while(ch!='-'&&!isdigit(ch))ch=getchar();
        if(ch=='-')zf=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int k,m,n,x,y,z,cnt,ans;
    
    namespace poly{
        #define p 998244353
        vector<int>R;
        vector<int>get(int n){
            vector<int>ret(n);
            for(rt i=0;i<n;i++)ret[i]=read();
            return ret;
        }
        void print(const vector<int>A){for(auto i:A)write((i+p)%p),putchar(' ');}
        int ksm(int x,int y=p-2){
            int ans=1;
            for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
            return ans;
        }
        void NTT(int n,vector<int>&A,int fla){
            A.resize(n);
            for(rt i=0;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]);
            for(rt i=1;i<n;i<<=1){
                int w=ksm(3,(p-1)/2/i);
                for(rt j=0;j<n;j+=i<<1){
                    int K=1;
                    for(rt k=0;k<i;k++,K=1ll*K*w%p){
                        int x=A[j+k],y=1ll*K*A[i+j+k]%p;
                        A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p;
                    }
                }
            }
            if(fla==-1){
                reverse(A.begin()+1,A.end());
                int invn=ksm(n);
                for(rt i=0;i<n;i++)A[i]=1ll*A[i]*invn%p;
            }
        }
        vector<int>Resize(int n,vector<int>A){A.resize(n);return A;}
        vector<int>Mul(vector<int>x,vector<int>y){
            int lim=1,sz=x.size()+y.size()-1;
            while(lim<=sz)lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            NTT(lim,x,1);NTT(lim,y,1);
            for(rt i=0;i<lim;i++)x[i]=1ll*x[i]*y[i]%p;
            NTT(lim,x,-1);x.resize(sz);
            return x;
        }
        vector<int>Inv(vector<int>A,int n=-1){
            if(n==-1)n=A.size();
            if(n==1)return vector<int>(1,ksm(A[0]));
            vector<int>b=Inv(A,(n+1)/2);
            int lim=1;while(lim<=n+n)lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            A.resize(n);NTT(lim,A,1);NTT(lim,b,1);
            for(rt i=0;i<lim;i++)A[i]=1ll*b[i]*(2ll-1ll*A[i]*b[i]%p)%p;
            NTT(lim,A,-1);A.resize(n);
            return A;
        }
        vector<int>Div(vector<int>A,vector<int>B){
            int n=A.size(),m=B.size();
            reverse(A.begin(),A.end());
            reverse(B.begin(),B.end());
            A.resize(n-m+1),B.resize(n-m+1);
            int lim=1;while(lim<=2*(n-m+1))lim<<=1;R.resize(lim);
            for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1);
            vector<int>ans=Resize(n-m+1,Mul(A,Inv(B)));
            reverse(ans.begin(),ans.end());
            return ans;
        }
        vector<int>Add(vector<int>A,vector<int>B){
            int len=max(A.size(),B.size());A.resize(len);
            for(rt i=0;i<len;i++)(A[i]+=B[i])%=p;
            return A;
        }
        vector<int>Sub(vector<int>A,vector<int>B){
            int len=max(A.size(),B.size());A.resize(len);
            for(rt i=0;i<len;i++)(A[i]-=B[i])%=p;
            return A;
        }
        vector<int>Mul(int x,vector<int>A){
            for(rt i=0;i<A.size();i++)A[i]=1ll*A[i]*x%p;
            return A;
        }
        vector<int>deriv(vector<int>A){//求导 
            for(rt i=1;i<A.size();i++)(A[i-1]=1ll*A[i]*i%p);
            A.pop_back();return A;
        }
        vector<int>integ(vector<int>A){//积分 
            A.push_back(0);
            for(rt i=A.size()-2;i>=0;i--)A[i+1]=1ll*A[i]*ksm(i+1)%p;
            A[0]=0;return A;
        }
        vector<int>Ln(const vector<int>A){return integ(Resize(A.size()-1,Mul(deriv(A),Inv(A))));}
        vector<int>Exp(vector<int>A,int n=-1){
            if(n==-1)n=A.size();
            if(n==1)return vector<int>(1,1);
            vector<int>A0=Resize(n,Exp(A,(n+1)>>1));
            vector<int>now=Resize(n,Ln(A0));
            for(rt i=0;i<n;i++)now[i]=(A[i]-now[i])%p;now[0]++;
            return Resize(n,Mul(A0,now));
        }
        struct cp{
            ll a,b,z;//a+bsqrt(z)
            cp operator *(const cp s)const{
                return {(1ll*a*s.a%p+1ll*b*s.b%p*z%p)%p,(1ll*a*s.b%p+1ll*b*s.a)%p,z};
            }
        };
        cp ksm(cp x,int y){
            cp ans={1,0,x.z};
            for(rt i=y;i;i>>=1,x=x*x)if(i&1){
                ans=x*ans;
            }
            return ans;
        }
        int Sqrt(int n){//求二次剩馀 
            if(ksm(n,(p-1)/2)!=1)return -1;
            while(1){
                x=rand()%p;
                if(ksm((1ll*x*x%p-n%p+p)%p,(p-1)/2)==1)continue;
                cp ret=ksm({x,1,(1ll*x*x%p+p-n)%p},(p+1)/2);        
                return min(ret.a,p-ret.a);
            }
        }
        vector<int>GetSqrt(vector<int>A,int n=-1){
            if(n==-1)n=A.size();
            if(n==1)return vector<int>(1,Sqrt(A[0]));
            vector<int>ans=Resize(n,GetSqrt(A,n+1>>1)),C(A.begin(),A.begin()+n);
            return Resize(n,Mul(ksm(2),Add(ans,Mul(Inv(ans),C))));
        }
        vector<int>Pow(vector<int>A,int k){
            A[0]=1;
            return Exp(Mul(k,Ln(A)));
        }
        //#undef p
    }; 
    using namespace poly;
    int inv[100010],v[100010];
    int main(){
        n=read();m=read();
        for(rt i=1;i<=m;i++){
            int a=read(),b=read();
            if(1ll*a*(b+1)<=n&&b)v[a*(b+1)]--;
            if(a<=n)v[a]++;
        }
        inv[0]=inv[1]=1;
        for(rt i=2;i<=n;i++)inv[i]=1ll*inv[p%i]*(p-p/i)%p;
        vector<int>ans(n+1); 
        for(rt i=1;i<=n;i++)if(v[i])
        for(rt j=1;i*j<=n;j++)(ans[i*j]+=1ll*v[i]*inv[j]%p)%=p;
        ans=Exp(ans);
        for(rt i=1;i<=n;i++)writeln((ans[i]+p)%p);
        return flush(),0;
    }
  • 相关阅读:
    工作量单位-人月、人日、人时 详解
    PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数详解
    常用的Mysql数据库操作语句大全
    Linux服务器,PHP的10大安全配置实践
    PHP如何获取二个日期的相差天数?
    常见HTTP状态码列表
    PHP中静态(static)调用非静态方法详解
    PHP引用(&)初探:函数的引用返回
    PHP的大括号(花括号{})使用详解
    详解JavaScript中的Url编码/解码,表单提交中网址编码
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10176273.html
Copyright © 2011-2022 走看看