2016 Multi-University Training Contest 1 solutions BY HIT
昨天多校第一次,重温了一下好久没体验过的爆零的感觉。
不知道是谁很早就做出来了1007题,和队友看了一个小时的1007。组合数学摆了半天越搞越晕。
我弃了搞1001。谁知道一搞就是“永生”。
我要贴的代码和网上能搜到的也是大同小异。
个人觉得1001的难点主要在两处:
1)发现:每一条边的期望等于边两端的点的数量的积乘上边的长度 这个规律。
2)如何求出每条边两端的点数。
其实1)应该不难发现,因为任意两个点都要两两配对,所以一端的点要去另外一端当然要”使用“这条边。而我当时傻逼的认为,只跟这条边的两个点上连接的点的数量有关……
2)需要一定的图论和dfs功底
【代码】
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a));
#define LL long long
#define maxn 100005
#define mod 100000007
struct Edge
{
int u,v,w;
}e[2000005];
struct node
{
int to,w,next;
}edge[maxn];
int head[maxn],n,m,tot;
void addedge(int u,int v,int w)
{
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].w=w;
head[u]=tot++;
}
bool cmp(Edge n1,Edge n2)
{
return n1.w<n2.w;
}
int p[maxn],r[maxn];
int find(int x)
{
if(p[x]==-1) return x;
return p[x]=find(p[x]);
}
LL ans;
void Krusal()
{
REP(i,0,m)
{
int u=e[i].u;
int v=e[i].v;
int w=e[i].w;
int a=find(u);
int b=find(v);
if(a==b)
continue;
if(r[a]>r[b])
p[b]=a;
else
{
p[a]=b;
if(r[a]==r[b])
r[b]++;
}
addedge(u,v,w);
addedge(v,u,w);
ans+=w;
}
}
LL sum[maxn],ans2;
void dfs(int root,int father)
{
sum[root]=1;
for(int i=head[root];i!=-1;i=edge[i].next)
{
int son=edge[i].to;
int w=edge[i].w;
if(son==father) continue; //如果回到了父亲节点
dfs(son,root);
sum[root] += sum[son];
ans2+=sum[son]*(n-sum[son])*w;
}
}
int main()
{
// freopen("out.txt","w",stdout);
int t;
scan(t);
while(t--)
{
scann(n,m);
REP(i,0,m)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
mst(head,-1); tot=ans=0;
mst(p,-1) mst(r,0);
sort(e,e+m,cmp);
Krusal();
mst(sum,0);
ans2=0;
dfs(1,-1);
printf("%I64d %.2lf\n",ans,ans2*1.0/((LL)n*(n-1)/2));
}
return 0;
}