zoukankan      html  css  js  c++  java
  • CF981H K Paths

    CF981H K Paths 

    题解

    一道不错的分治ntt题目

    题目稍微转化一下,就是所有k条链的存在交,并且交的部分都被覆盖k次

    所以一定是两个点,之间路径选择k次,然后端点两开花

    f[x]表示x子树内往下延伸k条链(可以停在x)的方案数(有标号)

    每个子树选择一个或者不选择,最多一共选择k个,dp是O(n^2)的,

    考虑生成函数,其实就是:

    统计答案?

    直接两两点对f相乘肯定不行,因为f仅仅是子树

    考虑枚举x作为lca统计

    如果是拐弯的链,树形DP即可。

    而如果是直上直下的链,

    对于不同子树,x的选择是扣去这个子树,还可以往上选择

    分治NTT的经典问题

    const int N=1e5+5;
    int n,k;
    int jie[N],inv[N];
    int A(int n,int m){
        if(n<0||m<0||n<m) return 0;
        return mul(jie[n],inv[n-m]);
    }
    int val[N],si[N];
    void divi(int l,int r,Poly &f,Poly &g){
        // cout<<" divi "<<l<<" "<<r<<endl;
        if(l==r){
            g.resize(1);g[0]=val[l];
            f.resize(2);f[0]=1;f[1]=si[l];
            return;
        }
        Poly lf,lg,rf,rg;
        int mid=(l+r)>>1;
        divi(l,mid,lf,lg);
        divi(mid+1,r,rf,rg);
        f=lf*rf;
        g=(lf*rg)+(lg*rf);
    }
    int f[N],sum[N],son[N];
    int ans,sz[N];
    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){
        // cout<<" xx "<<x<<" fa "<<fa<<endl;
        sz[x]=1;
        int pre=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            ++son[x];
            dfs(y,x);
            sz[x]+=sz[y];
            sum[x]=ad(sum[x],sum[y]);
            ans=ad(ans,mul(pre,sum[y]));
            pre=ad(pre,sum[y]);
        }
        if(son[x]){
            Poly F,G;
            int ct=0;
            for(reg i=hd[x];i;i=e[i].nxt){
                int y=e[i].to;
                if(y==fa) continue;
                val[++ct]=sum[y];
                si[ct]=sz[y];
            }
            divi(1,ct,F,G);
            Poly T;
            T.resize(2);
            T[0]=1;T[1]=n-sz[x];
            G=G*T;
            for(reg i=0;i<=min(k,son[x]);++i){
                // cout<<"F["<<i<<"] "<<F[i]<<" G["<<i<<"] "<<G[i]<<endl;
                ans=ad(ans,mul(A(k,i),G[i]));
                f[x]=ad(f[x],mul(A(k,i),F[i]));
            }
            sum[x]=ad(sum[x],f[x]);
        }else{
            f[x]=1;sum[x]=1;
        }
        // cout<<" return "<<x<<" f "<<f[x]<<endl;
    }
    int main(){
        rd(n);rd(k);
        if(k==1){
            ans=(ll)n*(n-1)/2%mod;
            ot(ans);return 0;
        }
        jie[0]=1;
        for(reg i=1;i<=k;++i) jie[i]=mul(jie[i-1],i);
        inv[k]=qm(jie[k],mod-2);
        for(reg i=k-1;i>=0;--i) inv[i]=mul(inv[i+1],i+1);
    
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);add(x,y);add(y,x);
        }
        dfs(1,0);
        ot(ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/4/8 18:57:00
    */
  • 相关阅读:
    centos7下配置时间同步服务器
    交换机简单配置(转)
    ubuntu16.04安装docker CE
    docker下使用DB2
    iptables之centos6版本详解
    iptables之centos6版本常用设置
    iptables介绍iptables和netfilter
    git的使用学习(九)搭建git服务器
    js 图片预览
    ps -ef | grep java 查看所有关于java的进程
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10988527.html
Copyright © 2011-2022 走看看