• LOJ 3399 -「2020-2021 集训队作业」Communication Network(推式子+组合意义+树形 DP)


    题面传送门

    一道推式子题。

    首先列出柿子,(ans=sumlimits_{T_2}|T_1cap T_2|·2^{T_1cap T_2})

    这个东西没法直接处理,不过注意到有一个柿子 (f(S)=sumlimits_{Tsubseteq S}sumlimits_{T'subseteq T}(-1)^{T-T'}f(T')),证明可考虑计算每个 (T') 的贡献,由于 (T'subseteq Tsubseteq S)(T) 必然是 (T')(S-T') 的某个子集的并,于是我们尝试枚举这个子集的大小,可得 (T') 在对这个柿子结果的贡献为 (f(T')sumlimits_{i=0}^{|S-T'|}dbinom{|S-T'|}{i}(-1)^i=0^{|S-T'|}·f(T')),因此只有当 (T'=S) 时对结果产生 (f(T')) 的贡献,其余 (T') 的贡献均为 (0),得证。

    考虑将这个柿子应用于这道题上,记 (f(S)=|S|·2^{|S|}),那么

    [egin{aligned} ans&=sumlimits_{T_2}f(T_1cap T_2)\ &=sumlimits_{T_2}sumlimits_{Ssubseteq(T_1cap T_2)}sumlimits_{Tsubseteq S}f(T)(-1)^{|S|-|T|}\ &=sumlimits_{Sin T_1}sumlimits_{Tsubseteq S}f(T)(-1)^{|S|-|T|}(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}sumlimits_{Tsubseteq S}2^{|T|}·|T|·(-1)^{|S|color{red}{+}|T|}(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}(-1)^{|S|}sumlimits_{Tsubseteq S}(-2)^{|T|}·|T|·(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}(-1)^{|S|}sumlimits_{i=0}^{|S|}(-2)^i·i·dbinom{|S|}{i}·(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}(-1)^{|S|}sumlimits_{i=0}^{|S|}(-2)^i·|S|·dbinom{|S|-1}{i-1}·(sumlimits_{Sin T_2}1)& ext{(吸收恒等式)}\ &=sumlimits_{Sin T_1}(-1)^{|S|}·|S|·sumlimits_{i=0}^{|S|-1}(-2)^{i+1}·dbinom{|S|-1}{i}·(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}(-1)^{|S|}·|S|·(-2)·sumlimits_{i=0}^{|S|-1}(-2)^{i}·dbinom{|S|-1}{i}·1^{|S|-1-i}·(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}(-1)^{|S|}·|S|·(-2)·(-1)^{|S|-1}·(sumlimits_{Sin T_2}1)\ &=sumlimits_{Sin T_1}2|S|·(sumlimits_{Sin T_2}1) end{aligned} ]

    推到这里,聪明的你一定已经发现,(sumlimits_{Sin T_2}1) 就是包含 (S) 当中边的生成树个数,于是题目要求的就是对于所有边集 (S),包含 (S) 的生成树个数乘上 (S) 的大小之和,而又根据我们在这里推得的结论:包含 (S) 的生成树个数就是 (n^{r-2}prodlimits_{i=1}^ra_i),其中 (r)(S) 中的边形成的连通块个数,(a_1,a_2,cdots,a_r) 为这 (r) 个连通块的大小。

    于是答案可进一步可进一步写成 (2sumlimits_{Sin T_1}|S|n^{r-2}prodlimits_{i=1}^ra_i=dfrac{2}{n^2}sumlimits_{Sin T_1}|S|prodlimits_{i=1}^rna_i),此时这玩意儿的组合意义就异常明显了:选择一个边集将这棵树分成若干个连通块,再从每个连通块中选择一个点,产生 (n) 的乘积贡献,最后从选定的边集中选择一条边,球所有选法的贡献之和。

    这样就可以 DP 了,(dp_{u,0/1,0/1}) 表示确定了以 (u) 为根的子树内连通块的划分情况,(u) 所在的连通块是否选择了点,(u) 子树内是否有边被选择的方案数,树上背包转移即可。

    时间复杂度 (mathcal O(16n))(虽然我深知这个写法非常不规范/cy/cy)

    const int MAXN=2e6;
    const int MOD=998244353;
    int qpow(int x,int e){
    	int ret=1;
    	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
    	return ret;
    }
    int n,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
    void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
    int dp[MAXN+5][2][2],tmp[2][2];
    void dfs(int x,int f){
    	dp[x][0][0]=1;dp[x][1][0]=n;
    	for(int e=hd[x];e;e=nxt[e]){
    		int y=to[e];if(y==f) continue;dfs(y,x);fill0(tmp);
    		for(int p=0;p<2;p++) for(int q=0;q<2;q++)//not seperate and not choose
    			for(int u=0;u+p<2;u++) for(int v=0;v+q<2;v++)
    				tmp[u+p][v+q]=(tmp[u+p][v+q]+1ll*dp[x][p][q]*dp[y][u][v])%MOD;
    		for(int p=0;p<2;p++) for(int u=0;u+p<2;u++) tmp[u+p][1]=(tmp[u+p][1]+1ll*dp[x][p][0]*dp[y][u][0])%MOD;//not seperate and choose
    		for(int p=0;p<2;p++) for(int q=0;q<2;q++) for(int v=0;v+q<2;v++)//seperate
    			tmp[p][v+q]=(tmp[p][v+q]+1ll*dp[x][p][q]*dp[y][1][v])%MOD;
    		for(int p=0;p<2;p++) for(int q=0;q<2;q++) dp[x][p][q]=tmp[p][q];
    	} //printf("%d %d %d %d %d
    ",x,dp[x][0][0],dp[x][0][1],dp[x][1][0],dp[x][1][1]);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
    	dfs(1,0);printf("%d
    ",2ll*qpow(n,MOD-3)*dp[1][1][1]%MOD);
    	return 0;
    }
    
  • 相关阅读:
    富可视M310刷机包 MIUIV5 红米开发版 闪光 美化 稳定
    Windowsclient SSH 远程连接Windowsserver(PowerShell Server)
    数据结构与算法02--链表基础
    rhadoop linear regression 问题
    奇怪的git代理超时问题
    怎样利用Heartbeat与Floating IP在Ubuntu 14.04上创建高可用性设置
    IVS_原理
    NN入门
    算法体系
    CNN原理
  • 原文地址:https://www.cnblogs.com/ET2006/p/loj-3399.html
Copyright © 2020-2023  润新知