• P6789 寒妖王


    P6789 寒妖王

    链接

    P6789 寒妖王

    题解

    月赛的时候暴力都没打对,我是真的菜。。
    现在想想Fading在月赛的时候就已经跟我说过正解了,但我当时没听懂。
    首先n<=15,求最大生成环套树的期望,考虑状压。
    对于每条边肯定是要分别讨论在所有情况中的贡献。把边按照边权从大到小排序,权值小的边对权值大的边是没有影响的。
    从大到小放入边的时候,一条边E(u,v)有贡献的情况有两种。
    1.两端点u,v在同一联通块且所在联通块是一颗树。
    2.两端点u,v不在同一联通块,且两个块至少有一个是树。
    (不是树的那个联通块有几个环不重要,因为在最后选边集的时候只会在那里选一个基环树)
    于是可以DP了QAQ。。
    f[i][S]表示前i条边与点集S有交的边形成极大的恰好包含S的联通块的方案数。
    g[i][S]表示前i条边与点集S有交的边形成极大的敲好包含S的数的方案数。
    加入某条边时,枚举包含边的两个端点的点集S,
    (f_{i,S}) (=) (2 cdot f_{i-1,S} + sum_{u in A , v in (S-A)}{f_{i-1,A} cdot f_{i-1,S-A}})
    (g_{i,S}) (=) (g_{i-1,S} + sum_{u in A , v in (S-A)}{g_{i-1,A} cdot g_{i-1,S-A}})
    然后就能按照之前的两种情况统计答案了。
    不过对于某个点集S,在前i条边中有些与点集没有交,这些边与当前要计算贡献的边是无关的,可以预处理有多少这样的边,然后乘上2的几次方就好。
    总效率是(O(m3^{n}))

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=3e5+10;
    const LL P=998244353;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    LL qpow(LL x,LL y){
    	LL re=1;
    	while(y){
    		if(y&1) re=re*x%P;
    		y>>=1;x=x*x%P;
    	}
    	return re;
    }
    int n,m;
    struct edge{int l,r;LL w;}e[70];
    bool cmp(edge x,edge y){return x.w>y.w;}
    LL g[(1<<15)+10],f[(1<<15)+10],sz[(1<<15)+10];
    LL bin[100];
    int main(){
    	bin[0]=1;for(int i=1;i<=70;++i) bin[i]=(bin[i-1]+bin[i-1])%P;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i) 
    		scanf("%d%d%lld",&e[i].l,&e[i].r,&e[i].w);
    	sort(e+1,e+1+m,cmp);
    	for(int i=0;i<n;++i){
    		g[(1<<i)]=1;
    		f[(1<<i)]=1;
    	}
    	int x,U,V,S,A,B;
    	LL ans=0,re,now;
    	for(int i=1;i<=m;++i){
    		x=(1<<(e[i].l-1))+(1<<(e[i].r-1));
    		//贡献
    		V=(1<<n)-1-x;U=V;re=0;
    		for(U=V;;U=(U-1)&V){
    			now=f[U+x]-g[U+x];
    			//S=U+x;
    			for(A=U;;A=(A-1)&U){
    				now+=(f[A+(1<<(e[i].l-1))]-g[A+(1<<(e[i].l-1))])*(f[U-A+(1<<(e[i].r-1))]-g[U-A+(1<<(e[i].r-1))])%P;
    				if(A==0) break;
    			}
    			now=(now%P+P)%P;
    			now=now*bin[sz[U+x]]%P;
    			re+=now;
    			if(U==0) break;
    		}
    		re=re*bin[m-i]%P;
    		re=(bin[m-1]-re+P)%P;
    		re=re*e[i].w%P;
    		ans+=re;
    		//转移 
    		V=(1<<n)-1-x;U=V;
    		for(U=V;;U=(U-1)&V){
    			//S=U+x;
    			sz[U]++;
    			f[U+x]=(f[U+x]+f[U+x]);if(f[U+x]>=P) f[U+x]-=P;
    			for(A=U;;A=(A-1)&U){
    				g[U+x]=(g[U+x]+g[A+(1<<(e[i].l-1))]*g[U-A+(1<<(e[i].r-1))])%P;
    				f[U+x]=(f[U+x]+f[A+(1<<(e[i].l-1))]*f[U-A+(1<<(e[i].r-1))])%P;
    				if(A==0) break;
    			}
    			if(U==0) break;
    		}
    	}
    	ans=(ans%P+P)%P;
    	ans=ans*qpow(bin[m],P-2)%P;
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    flush table with read lock的轻量级解决方案
    Linux进程关系(转载)
    常用的linux系统监控命令
    MySQL 5.7 InnoDB缓冲池NUMA功能支持——但是别高兴的太早
    网站收集ing....
    【转】程序设计语言中的 一等公民,二等公民,三等公民
    sbt修改为阿里云镜像
    java 中的原始类型与原始封装类型
    【转】MySql中row_number()、rank()、dense_rank() 的区别
    WPS_word使用
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/13689614.html
Copyright © 2020-2023  润新知