zoukankan      html  css  js  c++  java
  • 【XSY3163】Tree Ext【二分】【最小生成树】【矩阵树定理】【拉格朗日插值】

    给一张 n 个点 m 条边的无向连通图,每条边是黑边或白边 ,有边权。问有多少棵恰好有k条白边,且在此前提下边权和最小的生成树。mod 1e9+7。
    首先看一看这道题。
    ACM Live Archieve 7138
    这里有一个无比良心的题解。
    这里写链接内容
    膜拜这位不知名的ACM大神!
    由于发现博主已经两年多没更新了,这个网站可能会隔,蒟蒻截了张图。。。如果侵权,马上删除。
    这里写图片描述
    对于恰好k条白边的要求,我们可以二分一个权,给每条白边加上这个权,再最小生成树,注意相同边权白边排前面,如果最小生成树中白边数量>=k判定为可行,否则判定为不可行。
    这不就是bzoj2654吗?
    最后这题要求的是最小生成树计数,不是生成树计数。不过我们可以通过乘法原理和分段的思想转化为多次生成树计数。这不就是bzoj1016吗?
    因为某些玄学bug一直WA30分QAQ
    注意可能相同边权的边全部连了之后,各个联通块仍然不连通,所以要提前在他们之间连一些黑边,不影响答案。
    题解链接
    其实是把三道题强行拼在一起qwq

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cassert>
    #define int long long
    using namespace std;
    const int N=105,M=10005,mod=1000000007;
    int n,m,k,l,r,mid,tot,fa[N],pa[N],res[N],ans[N],tmp[N],id[N],num[N],x[N],y[N];
    struct edge{
        int u,v,d,c;
    }e[M];
    bool cmp(edge a,edge b){
        return a.d==b.d?a.c<b.c:a.d<b.d;
    }
    int find(int u){
        return u==fa[u]?u:fa[u]=find(fa[u]);
    }
    int get(int u){
        return u==pa[u]?u:pa[u]=get(pa[u]);
    }
    bool check(){
        for(int i=1;i<=m;i++){
            if(!e[i].c){
                e[i].d+=mid;
            }
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n;i++){
            fa[i]=i;
        }
        int cnt=0;
        for(int i=1,j=0;j<n-1;i++){
            int u=find(e[i].u),v=find(e[i].v);
            if(u!=v){
                fa[v]=u;
                j++;
                if(!e[i].c){
                    cnt++;
                }
            }
        }
        for(int i=1;i<=m;i++){
            if(!e[i].c){
                e[i].d-=mid;
            }
        }
        return cnt>=k;
    }
    int fastpow(int a,int x){
        a%=mod;
        int res=1;
        while(x){
            if(x&1){
                res=res*a%mod;
            }
            x>>=1;
            a=a*a%mod;
        }
        return res;
    }
    int solve(int l,int r,int x){
        static int a[N][N];
        memset(a,0,sizeof(a));
        for(int i=l;i<=r;i++){
            int u=id[find(e[i].u)],v=id[find(e[i].v)];
            if(u==v){
                continue;
            }
            if(e[i].c){
                a[u][u]++;
                a[v][v]++;
                a[u][v]--;
                a[v][u]--;
            }else{
                a[u][u]+=x;
                a[v][v]+=x;
                a[u][v]-=x;
                a[v][u]-=x;
            }
        }
        memcpy(pa,fa,sizeof(fa));
        for(int i=2;i<=tot;i++){
            int u=get(num[i]),v=get(num[i-1]);
            if(u!=v){
                pa[v]=u;
                a[i][i]++;
                a[i-1][i-1]++;
                a[i][i-1]--;
                a[i-1][i]--;
            }
        }
        for(int i=1;i<=tot;i++){
            for(int j=1;j<=tot;j++){
                a[i][j]=(a[i][j]%mod+mod)%mod;
            }
        }
        int res=1;
        for(int i=1;i<tot;i++){
            for(int j=i+1;j<tot;j++){
                if(a[j][i]){
                    int t=a[i][i]*fastpow(a[j][i],mod-2)%mod,tmp;
                    for(int k=i;k<tot;k++){
                        tmp=(a[i][k]-a[j][k]*t%mod+mod)%mod;
                        a[i][k]=a[j][k];
                        a[j][k]=tmp;
                    }
                    res=-res;
                }
            }
        }
        if(res==-1){
            res+=mod;
        }
        for(int i=1;i<tot;i++){
            res=res*a[i][i]%mod;
        }
        return res;
    }
    void lagerange(){
        static int a[N],b[N],c[N];
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        memset(res,0,sizeof(res));
        a[0]=1;
        for(int i=0;i<=tot;i++){
            b[0]=0;
            for(int j=1;j<=i+1;j++){
                b[j]=a[j-1];
            }
            for(int j=0;j<=i;j++){
                b[j]=(b[j]-x[i]*a[j]%mod+mod)%mod;
            }
            for(int j=0;j<=i+1;j++){
                a[j]=b[j];
            }
        }
        for(int i=0;i<=tot;i++){
            for(int j=0;j<=tot+1;j++){
                b[j]=a[j];
            }
            for(int j=tot+1;j>=1;j--){
                c[j-1]=b[j];
                b[j-1]=(b[j-1]+1LL*b[j]*x[i]%mod)%mod;
            }
            int tmp=1;
            for(int j=0;j<=tot;j++){
                if(j!=i){
                    tmp=tmp*(x[i]-x[j]+mod)%mod;
                }
            }
            tmp=y[i]*fastpow(tmp,mod-2)%mod;
            for(int j=0;j<=tot;j++){
                c[j]=c[j]*tmp%mod;
                res[j]=(res[j]+c[j])%mod;
            }
        }
    }
    signed main(){
        scanf("%lld%lld%lld",&n,&m,&k);
        for(int i=1;i<=m;i++){
            scanf("%lld%lld%lld%lld",&e[i].u,&e[i].v,&e[i].d,&e[i].c);
        }
        l=-1e9-1,r=1e9+1;
        while(l<r){
            mid=(l+r+1)/2;
            if(check()){
                l=mid;
            }else{
                r=mid-1;
            }
        }
        for(int i=1;i<=m;i++){
            if(!e[i].c){
                e[i].d+=l;
            }
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n;i++){
            fa[i]=i;
        }
        ans[0]=1;
        for(l=1;l<=m;l=r+1){
            r=l;
            while(r<m&&e[r+1].d==e[l].d){
                r++;
            }
            memset(id,0,sizeof(id));
            tot=0;
            for(int i=l;i<=r;i++){
                int u=find(e[i].u),v=find(e[i].v);
                if(u!=v){
                    if(!id[u]){
                        id[u]=++tot;
                        num[tot]=u;
                    }
                    if(!id[v]){
                        id[v]=++tot;
                        num[tot]=v;
                    }
                }
            }
            if(!tot||tot==1){
                continue;
            }
            memcpy(pa,fa,sizeof(fa));
            for(int i=l;i<=r;i++){
                int u=find(e[i].u),v=find(e[i].v);
                if(u!=v){
                    fa[v]=u;
                }
            }
            for(int i=0;i<=tot;i++){
                x[i]=i+1;
                y[i]=solve(l,r,i+1);
            }
            lagerange();
            memset(tmp,0,sizeof(tmp));
            for(int i=0;i<n;i++){
                for(int j=0;i+j<n;j++){
                    tmp[i+j]+=ans[i]*res[j]%mod;
                    tmp[i+j]%=mod;
                }
            }
            memcpy(ans,tmp,sizeof(tmp));
        }
        for(int i=2;i<=n;i++){
            if(find(i)!=find(1)){
                puts("0");
                return 0;
            }
        }
        printf("%lld
    ",ans[k]);
        return 0;
    }
  • 相关阅读:
    二、魔法函数
    Metaclasses
    一、python中的一切皆对象
    三、鸭子类型
    SQL进行排序、分组、统计的10个新技巧
    输入地址栏可以编辑页面的js
    项目开发中常用JS表单取值方法
    [导入]通用的分页存储过程
    107个常用Javascript语句
    [导入]事务处理
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476830.html
Copyright © 2011-2022 走看看