• day6-马耀华


    T3AT3980 [ARC093C] Bichrome Spanning Tree

    在一张图上黑白染色,使得同时包含有黑边和白边的最小生成树权值恰好为X。问有多少种染色方法?

    (n <= 1000 , m <= 2000)

    先求出不管黑白边的MST,然后记 det 为X与之的差值。

    之后对于每条非MST边 , 求出它的权值-树上的边的最大值 , 记这个值为val。

    那么对于val分类,$ < det$ 的记为cnt0 , (= det) 记为cnt1 , (> det) 记为cnt2。

    然后分类讨论。

    (del < 0) 肯定不合法。

    (del = 0)

    有两种情况,一种是最开始的MST就合法,这种方案数是((2 ^ {n - 1} - 2) * 2 ^ {m - n + 1}) 解释一下,就是枚举树上边的染色方案,但是有全黑和全白不能要,再给它乘上非树边的贡献。

    还有一种是,最开始的那个不合法,需要给他换边,方案数是(2 * (2 ^ {cnt1} - 1) * 2 ^ {cnt2}) 解释一下就是先枚举最开始的MST是全黑还是全白,然后要保证 cnt1 条 val = det 的边至少存在一条能被替换, 对于cnt2的边是不会被用到的所以可以随便,对于cnt0的边不能选,要不然权值会更小,但这显然不合法。

    (det = 1)

    那么一开始的MST肯定不能选,它的方案就是(del = 0)的第二种情况。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long LL;
    const int N = 1010 , mod = 1e9+7;
    #define int long long
    inline int read()
    {
    	register int x = 0 , f = 0; register char c = getchar();
    	while(c < '0' || c > '9') f |= c == '-' , c = getchar();
    	while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
    	return f ? -x : x;
    }
    int n , m , cnt , del , goal , mx;
    int fa[N] , head[N] , used[N << 1];
    struct node{ int u , v , w; bool operator < (const node &A) const { return w < A.w; }; }E[N << 1];
    struct edge{ int v , nex , c; }e[N << 1];
    inline void add(int u , int v , int c) { e[++cnt].v = v; e[cnt].nex = head[u]; e[cnt].c = c; head[u] = cnt; }
    int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
    inline int Union(int x , int y)
    {
    	x = find(x); y = find(y); if(x == y) return 0;
    	fa[x] = y; return 1;
    }
    
    void dfs(int x , int fa , int m)
    {
    	if(x == goal) { mx = m; return ; }
    	for(int i = head[x] ; i && mx == -1 ; i = e[i].nex) if(e[i].v != fa) dfs(e[i].v , x , max(m , e[i].c));
    }
    
    int Query(int u , int v)
    {
    	goal = v; mx = -1; dfs(u , 0 , 0); return mx;
    }
    
    inline int ksm(int a , int k) { a %= mod; int ans = 1; for( ; k ; k >>= 1 , a = a * a % mod) if(k & 1) ans = ans * a % mod; return ans; }
    
    signed main()
    {
    	n = read(); m = read(); del = read();
    	for(int i = 1 ; i <= n ; ++i) fa[i] = i;
    	for(int i = 1 ; i <= m ; ++i) E[i].u = read() , E[i].v = read() , E[i].w = read();
    	sort(E + 1 , E + 1 + m);
    	for(int i = 1 ; i <= m ; ++i) if(Union(E[i].u , E[i].v)) add(E[i].u , E[i].v , E[i].w) , add(E[i].v , E[i].u , E[i].w) , del -= E[i].w , used[i] = 1;
    	if(del < 0) { puts("0"); return 0; }
    	int cnt0 = 0 , cnt1 = 0 , cnt2 = 0 , val;
    	for(int i = 1 ; i <= m ; ++i) if(!used[i])
    	{
    		val = E[i].w - Query(E[i].u , E[i].v);
    		if(val < del) cnt0++; else if(val == del) cnt1++; else cnt2++;
    	}
    	int ans = 2LL * (ksm(2 , cnt1) - 1) % mod * ksm(2 , cnt2) % mod;
    	if(del == 0) ans = (ans + (ksm(2 , n - 1) - 2) * ksm(2 , m - n + 1) % mod) % mod;
    	ans = (ans % mod + mod) % mod; cout << ans << '
    ';
    	return 0;
    }
    
    
  • 相关阅读:
    JDBC事务
    PreparedStatement预编译对象实现
    读取properties配置文件
    eclipse 快捷键总结
    JDBC编程六部曲
    JDBC 配置环境
    基于注解的DI(DI:Dependency Injection 依赖注入)
    基于XML的DI
    汇编call jmp理解
    常用jar包下载地址
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/13050939.html
Copyright © 2020-2023  润新知