zoukankan      html  css  js  c++  java
  • [DarkBZOJ3754] Tree之最小方差树

    前言

    感觉如果不讲做法应该要想上好一会,甚至可能做不出来。

    题目

    DarkBZOJ

    讲解

    拿到这道题很有可能没什么思路,我们就从暴力入手。

    先把标准差的公式写出来:

    [sqrt{frac{sum_{0le i<n}(a_i-overline{a})^2}{n}} ]

    对于这道题,显然我们知道生成树是 (n-1) 条边,而且外面的根号其实不影响相对大小,所以我们去掉这些东西( (a_i) 为边权):

    [sum (a_i-overline{a})^2 ]

    显然我们如果知道了 (overline{a}) 的大小,就可以通过最小生成树算法求出上面这个东西的最小值,可惜我们不知道。

    但我们真的不能知道吗?

    写出它的表达式:(overline{a}=frac{sum a_i}{n-1}) ,显然 (overline{a})(sum a_i) 决定,我们发现 (sum a_i) 最多不过 (10^4),直接枚举即可。

    但是这还不够,如果你枚举一次做一次 ( t Kruskal),发现复杂度达到了 (O(cnmlog_2m)),是有问题的。

    其实我们只需要一次排序,枚举一次的时候用双指针维护一下当前情况下权值 ((a_i-overline{a})) 最小,且原始权值 (a_i) 小于和大于平均值的边,并不难实现。

    于是复杂度就是 (O(mlog_2m+cnm))

    我真不想说脏话。(摊手

    代码

    不懂戳我
    //12252024832524
    #include <cmath>
    #include <cstdio>
    #include <cstring> 
    #include <algorithm>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 105;
    const int MAXM = 2005;
    const int INF = 0x3f3f3f3f;
    int n,m;
    double ans = INF;
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1) 
    {
    	if(x < 0) x = -x,putchar('-');
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    struct edge
    {
    	int u,v,w;
    	bool operator < (const edge &px)const{
    		return w < px.w;
    	}
    }e[MAXM];
    
    int f[MAXN];
    int findSet(int x){if(x^f[x])f[x]=findSet(f[x]);return f[x];}
    void unionSet(int u,int v){f[findSet(u)] = findSet(v);}
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); m = Read();
    	for(int i = 1;i <= m;++ i) e[i].u = Read(),e[i].v = Read(),e[i].w = Read();
    	sort(e+1,e+m+1);
    	e[0].w = -INF; e[m+1].w = INF;
    	for(int C = 1;C <= 100*(n-1);++ C)
    	{
    		for(int i = 1;i <= n;++ i) f[i] = i;
    		int cnt = n-1,s = 0; double av = C / (n-1.0),cur = 0;
    		int r = upper_bound(e+1,e+m+2,edge{0,0,(int)ceil(av)}) - e;
    		int l = r-1;
    		while(cnt)
    		{
    			while(l > 0 && findSet(e[l].u) == findSet(e[l].v)) --l;
    			while(r <= m && findSet(e[r].u) == findSet(e[r].v)) ++r;
    			double L = av-e[l].w,R = e[r].w-av;
    			if(L < R) cur += L*L,s += e[l].w,unionSet(e[l].u,e[l].v),--l;
    			else cur += R*R,s += e[r].w,unionSet(e[r].u,e[r].v),++r;
    			--cnt;
    		}
    		if(s == C) ans = Min(ans,sqrt(cur/(n-1)));
    	}
    	printf("%.4f",ans);
    	return 0;
    }
    
  • 相关阅读:
    javaScript系列 [35]HTML页面渲染的基本过程
    javaScript系列 [29] RegExp
    javaScript系列 [40]defineProperty
    javaScript系列 [32] type
    javaScript系列 [34]FormData
    javaScript系列 [39]deepClone
    javaScript系列 [33] new
    javaScript系列 [36]Call by sharing
    javaScript系列 [38]浏览器、HTML和内核(引擎)
    javaScript系列 [28] Event
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15362475.html
Copyright © 2011-2022 走看看