51Nod 算法马拉松21(迎新年)
这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =)。
讲讲比赛经过吧。
8:00准时发题,拿到之后第一时间开始读。
A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过读后面的题。
B完全二叉树的方差,大概看了一遍,好神的样子,跳过。
C多项式?好吧没学过FFT和NTT的我肯定不会,跳跳跳。
D最大值,哎呦这函数什么破玩意儿,看不懂,跳跳跳。
E B君的射击,卧槽毕克大人您出题就算了出这么一道码农题是要闹那样,跳跳跳。
F那些年,我们一起讲的故事,卧槽这特么简直就是道纯语文题,跳跳跳。
哎等等,跳没了……
好像A比较简单,先想想A算了……
第一思路是二分图最大权匹配,然后费用流暴力,一看数据范围这显然不靠谱,然后就开始思考问题的特殊性质。
不经意间按了几下F5,卧槽怎么你们做的那么快,看来是我想复杂了,这应该是个不太难的题。
想了想匹配的构造方法,贪心似乎不太可行,别的方法一时也想不出来,算了好像可以枚举每条边计算贡献……感觉像是对的,但是又对此深表怀疑……
中间又按了几次F5,卧槽你们做题怎么这么神速……看来这题确实简单,反正WA了也不会有惩罚,看我码一发枚举边计算贡献,随手一交,啊哈居然A了……
自己交的比较早,所以是第18个A的(为什么我记得是第19个……还是说是第19个提交的……),排名还不错……(机房其他人好多都第几十+才A的……)
看了看其他题,E题貌似之前看少了连通的圆可以使中间那块也变成洞,感觉自己并不会写。F题读了半天还是没读懂……D题的函数看懂了就是十进制位倒过来然后乱搞,然而还是没思路。C题也看了两眼,一看别人的运行时间都是十几ms,感觉像是O(1)的结论题,打了一发print input()(这是Python2)然而过不去样例……
然后开始搞B题,看见方差最小感觉像是一个三分平均数然后二分图最小权匹配,搞了半天搞出来新树直径的结论,然而并没有推出题解的神贪心,写了一发三分平均数+最小费用最大流(二分图最小权匹配),然后不知道哪儿写挂了,样例都过不去(也可能是函数根本不单峰……)……调了半天调不出来,狠狠心一交,1W19T,算了我弃疗……
脑子昏昏涨涨,就此弃疗。星期六和星期天也没有再来做题,由于第一题交的早,最终成绩rank60,真是便宜我了。(然而排名太低,Rating往下掉了……= =)
随便水水比赛就拿到了排名是20的倍数这个buff,话说运气真是好……
话说今天才收到点头盾,这速度我给差评……
给A题贴个题解:
既然要求匹配点的距离和最大,那么两条路径一定要尽可能相交(如果不相交,交换两条路径的端点不会变劣)。或者说,匹配路径一定要尽可能经过长的边。不过这还是不太好搞,所以放弃构造方法,考虑对每条边计算能出现在几条匹配路径中,也就是说能对答案产生多少贡献。
考虑一条长为w的边,设这条边连接的两个连通块的大小分别为a和b。为了保证距离和最大,我们需要使得尽量多的匹配路径经过这条边,所以应该尽量让边两端的点进行匹配,因此这条边最多经过min{a,b}次。
边与边之间互不影响(我不会证……),所以一遍dfs/bfs之后枚举每条边计算贡献即可。为了保险(防爆栈),我用的是bfs。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 const int maxn=100010; 7 struct edge{int u,v,w;}e[maxn]; 8 void bfs(); 9 vector<int>G[maxn]; 10 int n,q[maxn],prt[maxn]={0},size[maxn]={0}; 11 long long ans=0; 12 int main(){ 13 scanf("%d",&n); 14 for(int i=1;i<n;i++){ 15 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 16 G[e[i].u].push_back(e[i].v); 17 G[e[i].v].push_back(e[i].u); 18 } 19 bfs(); 20 for(int i=1;i<n;i++){ 21 if(prt[e[i].u]==e[i].v)swap(e[i].u,e[i].v); 22 int s=min(size[e[i].v],size[1]-size[e[i].v]); 23 ans+=(long long)s*e[i].w; 24 } 25 printf("%lld",ans); 26 return 0; 27 } 28 void bfs(){ 29 int head=0,tail=0; 30 q[tail++]=1; 31 while(head!=tail){ 32 int x=q[head++]; 33 size[x]=1; 34 for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=prt[x]){ 35 prt[G[x][i]]=x; 36 q[tail++]=G[x][i]; 37 } 38 } 39 for(int i=n;i;i--){ 40 int x=q[i]; 41 size[prt[x]]+=size[x]; 42 } 43 }
附官方题解:
(话说构造法真的可行嘛……我仍然理解不了贪心构造……只会写O(n2m2)的费用流……囧囧囧)
反思:
这次打比赛的时候有点着急,B题也没有耐心仔细想/写,发挥并不太好。
A题看见别人神速过题之后就有点慌了,一改求稳的作风,凭着直觉交了一份代码,能A估计是运气。今后的比赛或者是考试一定要求稳,毕竟无缘无故掉了几十分上百分可是很要命的。
下一站,UOJ Test Round #2。
加油。