• [WC2019] 数树


    [WC2019] 数树 

    Zhang_RQ题解(本篇仅概述)

     

    前言

    有进步,只做了半天。。。。

    一道具有极强综合性的数数好题!

    强大的多合一题目

    精确地数学推导和耐心。

    有套路又不失心意。

     

    融合了:

    算法:

    prufer序列及其扩展

    树形Dp

    容斥或者二项式定理

    EGF

    多项式Exp

     

    先要会:

    [学习笔记]prufer序列

    [学习笔记]多项式指数函数

    [学习笔记]生成函数

    luoguP4841 城市规划

    省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)

     

    然后开始刚题。

    就是:

    求各种情况下的y^(n-|T1∩T2|)的和

     

     

    OP=0

    哈希。

    OP=1

    枚举交集,统计符合的T2树的个数

    prufer序列森林版扩展

    但是会算重,连回去会多

    考虑重组贡献

    每个实际的$y^k$会被$k$小的时候计算,$y^k=(y+1-1)^k=∑C(j,i)(y-1)^i$

    发现,只要把贡献的$y$成$y-1$,就大功告成啦!

    $Pi szi$可以套路地组合意义成为每个连通块选择一个的方案数,然后就$f[i][0/1]$就O(n)辣

    注意每次选择交的边还有贡献

    这里,第二个$y^{-1}$运算的时候,要变成$(y^{-1}-1)$

    OP=2

    还是枚举交集的边

    发现和交集大小密切相关,所以枚举交集大小$s$​

    然后$gs$设出来,

    要枚举边再考虑连通块,不妨枚举连通块考虑贡献的边集

    连通块的分配$frac{n!}{(n-s)!}$,连通块内的连边$a^{a-2}$,连通块之间连边$Pi a_i *n^{m-2}$

    一些东西要平方

    把$gs$带回去,然后无关的都提到前面去

    把枚举连通块,变成EGF

    然后再变成多项式指数函数的形式,大功告成!

     

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=1e5+5;
    const int mod=998244353;
    const int G=3;
    const int GI=332748118;
    int n,Y;
    int mul(int x,int y){return (ll)x*y%mod;}
    int ad(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    il int sub(int x,int y){return ad(x,mod-y);}
    int qm(int x,int y){
        int ret=1;
        while(y){
            if(y&1) ret=mul(ret,x);
            x=mul(x,x);
            y>>=1;
        }
        return ret;
    }
    namespace sol0{
    map<pair<int,int>,int>mp;
    int cnt;
    void main(){
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);if(x>y) swap(x,y);mp[mk(x,y)]=1;
        }
        for(reg i=1;i<n;++i){
            rd(x);rd(y);if(x>y) swap(x,y);cnt+=mp[mk(x,y)];
        }
        printf("%d
    ",qm(Y,n-cnt));
    }
    
    }
    namespace sol1{
    ll f[N][2];
    int z;
    int cos,ivc;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    void dfs(int x,int fa){
        f[x][0]=f[x][1]=1;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            dfs(y,x);
            //jiao and no
            ll od0=f[x][0],od1=f[x][1];
            f[x][0]=ad(mul(od0,f[y][1]),mul(od0,mul(f[y][0],cos)));
            f[x][1]=ad(mul(od1,f[y][1]),ad(mul(od0,mul(f[y][1],cos)),mul(od1,mul(f[y][0],cos))));
        }
    }
    void main(){
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);add(x,y);add(y,x);
        }
        if(Y==1){
            printf("%d
    ",qm(n,n-2));
            return;
        }
        z=ad(qm(Y,mod-2),mod-1);
        cos=mul(z,qm(n,mod-2));
        ivc=qm(cos,mod-2);
    //    cout<<" cos "<<cos<<" ivc "<<ivc<<endl;
        dfs(1,0);
        ll ans=0;
        ans=mul(mul(qm(n,n-2),qm(Y,n)),f[1][1]);
        cout<<ans;
    }
    }
    namespace sol2{
    struct Poly{
        vector<int>f;
        Poly(){f.clear();}
        il int &operator[](const int &x){return f[x];}
        il const int &operator[](const int &x) const {return f[x];}
        il void resize(const int &n){f.resize(n);}
        il int size() const {return f.size();}
        il void cpy(Poly &b){f.resize(b.size());for(reg i=0;i<(int)f.size();++i)f[i]=b[i];}
        il void rev(){reverse(f.begin(),f.end());}
        il void clear(){f.clear();}
        il void read(const int &n){f.resize(n);for(reg i=0;i<n;++i)rd(f[i]);}
        il void out() const {for(reg i=0;i<(int)f.size();++i)ot(f[i]);putchar('
    ');}
    }R;
    il int init(const int &n){int m;for(m=1;m<n;m<<=1);return m;}
    il void rev(Poly &f){
        int lp=f.size();
        if(R.size()!=f.size()) {
            R.resize(f.size());
            for(reg i=0;i<lp;++i){
                R[i]=(R[i>>1]>>1)|((i&1)?lp>>1:0);
            }
        }
        for(reg i=0;i<lp;++i){
            if(i<R[i]) swap(f[i],f[R[i]]);
        }
    }
    il void NTT(Poly &f,int c){
        int n=f.size();rev(f);
        for(reg p=2;p<=n;p<<=1){
            int gen=(c==1)?qm(G,(mod-1)/p):qm(GI,(mod-1)/p);
            for(reg l=0;l<n;l+=p){
                int buf=1;
                for(reg k=l;k<l+p/2;++k){
                    int tmp=mul(f[k+p/2],buf);
                    f[k+p/2]=sub(f[k],tmp);
                    f[k]=ad(f[k],tmp);
                    buf=mul(buf,gen);
                }
            }
        }
        if(c==-1){
            int iv=qm(n,mod-2);for(reg i=0;i<n;++i) f[i]=mul(f[i],iv);
        }
    }
    il Poly Inv(const Poly &f,int n){
        if(n==1){
            Poly g;g.resize(1);g[0]=qm(f[0],mod-2);return g;
        }
        Poly g=Inv(f,(n+1)>>1),t;
        int m=init(n*2);
        t.resize(m);
        for(reg i=0;i<n;++i)t[i]=f[i];
        g.resize(m);
        NTT(g,1);NTT(t,1);
        for(reg i=0;i<m;++i)g[i]=mul(sub(2,mul(g[i],t[i])),g[i]);
        NTT(g,-1);g.resize(n);
        return g;
    }
    il void operator *=(Poly &f,Poly g){
        int st=f.size()+g.size()-1;
        int len=init(f.size()+g.size()-1);f.resize(len);g.resize(len);
        NTT(f,1);NTT(g,1);for(reg i=0;i<len;++i) f[i]=mul(f[i],g[i]);
        NTT(f,-1);
        f.resize(st);
    }
    il void operator *=(Poly &f,const int &c){for(reg i=0;i<f.size();++i) f[i]=mul(f[i],c);}
    il Poly operator *(Poly f,const Poly &g){f*=g;return f;}
    il Poly operator *(Poly f,const int &c){for(reg i=0;i<f.size();++i) f[i]=mul(f[i],c);return f;}
    il void operator +=(Poly &f,const Poly &g){for(reg i=0;i<f.size();++i) f[i]=ad(f[i],g[i]);}
    il void operator +=(Poly &f,const int &c){f[0]=ad(f[0],c);}
    il Poly operator +(Poly f,const Poly &g){for(reg i=0;i<f.size();++i) f[i]=ad(f[i],g[i]);return f;}
    il Poly operator +(Poly f,const int &c){f[0]=ad(f[0],c);return f;}
    il void operator -=(Poly &f,const Poly &g){for(reg i=0;i<f.size();++i) f[i]=sub(f[i],g[i]);}
    il void operator -=(Poly &f,const int &c){f[0]=sub(f[0],c);}
    il Poly operator -(Poly f,const Poly &g){for(reg i=0;i<f.size();++i) f[i]=sub(f[i],g[i]);return f;}
    il Poly operator -(Poly f,const int &c){f[0]=sub(f[0],c);return f;}
    il Poly operator ~(const Poly &f){return Inv(f,f.size());}
    il Poly operator /(Poly f,Poly g){int len=f.size()-g.size()+1;f.rev();g.rev();g.resize(len);f=f*(~g);f.resize(len);f.rev();return f;}
    il Poly operator %(Poly f,Poly g){Poly s=f/g;f=f-g*s;f.resize(g.size()-1);return f;}
    il Poly Inter(Poly f){int st=f.size();f.resize(st+1);for(reg i=st;i>=1;--i){f[i]=mul(f[i-1],qm(i,mod-2));}f[0]=0;return f;}
    il Poly Diff(Poly f){int st=f.size();for(reg i=0;i<st-1;++i) f[i]=mul(f[i+1],(i+1));f.resize(st-1);return f;}
    il Poly Ln(const Poly &f){Poly g=Diff(f),h=(~f);g=g*h;g.resize(f.size()-1);return Inter(g);}
    il Poly Exp(const Poly &f,int n){
        if(n==1){
            Poly g;g.resize(1);g[0]=1;
            return g;
        }
        Poly g=Exp(f,(n+1)>>1);
        g.resize(n);
        g=g*(((Ln(g)*(mod-1))+1)+f);
        g.resize(n);
        return g;
    }
    il Poly Exp(const Poly &f){
        return Exp(f,f.size());
    }
    int jie[N],inv[N];
    void main(){
        if(Y==1){
            printf("%d
    ",mul(qm(n,n-2),qm(n,n-2)));
            return;
        }
        int z=ad(qm(Y,mod-2),mod-1);
        Poly g;
        g.resize(n+1);
        
        int ivz=qm(z,mod-2);
        jie[0]=1;
        for(reg i=1;i<=n;++i) jie[i]=mul(jie[i-1],i);
        inv[n]=qm(jie[n],mod-2);
        for(reg i=n-1;i>=0;--i) inv[i]=mul(inv[i+1],i+1);
        
        for(reg j=1;j<=n;++j){
            g[j]=mul(mul(mul(mul(n,n),ivz),inv[j]),qm(j,j));
        }
        g=Exp(g);
        ll ans=mul(mul(mul(mul(qm(Y,n),jie[n]),qm(qm(n,mod-2),4)),qm(z,n)),g[n]);
        cout<<ans;
    }
    
    }
    int main(){
        int op;
        rd(n);rd(Y);rd(op);
        if(op==0) sol0::main();
        else if(op==1) sol1::main();
        else sol2::main();
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/4/12 15:09:42
    */
  • 相关阅读:
    Andriod一段时间未操作页面,系统自动登出
    Error:Execution failed for task ':app:clean'
    Handler的postDelayed(Runnable, long)
    Android Studio快捷键大全
    Cookie、Session、Token的区别
    CentOS 7 上安装jdk
    CentOS 7 上搭建nginx来部署静态网页
    PyCharm如何设置 “ctrl+滚轮” 实现字体的放大和缩小
    HTTP和HTTPS
    性能测试思想(What is performance testing?)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10698164.html
Copyright © 2020-2023  润新知