【AT3980】[ARC093C] Bichrome Spanning Tree(MST)

点此看题面

  • 给定一张(n)个点(m)条边的图,求有多少种给边黑白染色的方案,使得同时包含黑白边的最小生成树权值恰好为(v)
  • (nle10^3,mle2 imes10^3)

最小生成树

考虑先随便找出一棵最小生成树,设其权值为(t)

显然若(t>v)必然无解。

如果(t=v),那么原图中任何一棵最小生成树都是符合条件的。因此我们求出可能在最小生成树中的总边数(s),则只要这(s)条边不完全同色即可,因此答案为((2^s-2) imes 2^{m-s})

关键还是在于(t<v),显然这棵最小生成树上的所有边必然同色,否则它就成了同时包含黑白边的最小生成树。

根据最小生成树的性质,我们至多加入一条异色边去替换最小生成树中的一条边,因为用更多的边去替换必然权值更大。

那么我们就枚举最小生成树外的每条边,如果加入它权值仍然小于(v)则它也得同色,如果等于(v)那么它填成异色可以达成条件(记这种边数为(s1)),而如果大于(v)那么它填什么颜色都不会影响到最小生成树权值(记这种边数为(s2))。

由于最小生成树有两种颜色,而能够填成异色达成条件的边不能全为同色,因此答案就是(2 imes(2^{s1}-1) imes2^{s2})

代码:(O(nmalpha(n)))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
#define M 2000
#define X 1000000007
#define LL long long
using namespace std;
int n,m,pw[M+5],used[M+5];LL v;
struct edge {int x,y,v,u;I bool operator < (Con edge& o) Con {return v<o.v;}}e[M+5];
int f[N+5];I int fa(CI x) {return f[x]^x?f[x]=fa(f[x]):x;}//并查集
I LL MST(CI id)//强制选择id时的最小生成树
{
	RI i,fx,fy;LL t=0;for(i=1;i<=n;++i) f[i]=i;id&&(t=e[id].v,f[e[id].y]=e[id].x);//强制选择id
	for(i=1;i<=m;++i) (fx=fa(e[i].x))^(fy=fa(e[i].y))&&(t+=e[i].v,f[fy]=fx,e[i].u=1);return t;//最小生成树
}
int main()
{
	RI i;for(scanf("%d%d%lld",&n,&m,&v),pw[0]=i=1;i<=m;++i)
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v),pw[i]=2LL*pw[i-1]%X;sort(e+1,e+m+1);//把边按权值排序贪心
	RI s1=0,s2=0;LL t=MST(0);for(i=1;i<=m;++i) used[i]=e[i].u;if(t>v) return puts("0"),0;//t>v显然无解
	if(t==v) {for(i=1;i<=m;++i) MST(i)==v&&++s1;return printf("%d
",1LL*(pw[s1]-2)*pw[m-s1]%X),0;}//t=v求出可能在最小生成树上的边数
	for(i=1;i<=m;++i) !e[i].u&&((t=MST(i))==v?++s1:t>v&&++s2);return printf("%d
",2LL*(pw[s1]-1)*pw[s2]%X),0;//t<v求出异色能达成条件的边数和无影响的边数
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3980.html