BestCoder Round #1 解题报告
来源:互联网 发布:sabayon linux 中文 编辑:程序博客网 时间:2024/06/06 14:22
最近听到SPLAY学长说有一个网站叫BestCoder,题目质量挺不错,而且难度在NOIP提高组水平,比较适合我刷(重点是不像CF那样要翻墙,深夜打比赛,而且它还支持在HDU上提交)。于是我有空跑过去看了看,见到只有6页比赛嘛,于是决定从头开始做……但愿暑假能刷完吧。
T1:逃生
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=525&pid=1001
题目分析:刚打开这题就见到了陈老师……一开始我觉得让编号小的尽量靠前=字典序最小,然后觉得很水嘛,直到后来我举出了反例。然后我开始脑洞大开YY,但想出来的方法基本都是时间复杂度玄学。我感觉从前往后放有困难,于是试图从后面开始做。如果a要在b之前,就b向a连一条边,然后每一次选编号最大的入度为0的点,并删去它的出边,就可以保证编号小的尽可能靠前。我感觉这个方法跟我做过的一道POJ上的递归打印欧拉路径的题有点像,直觉告诉我这样做和原问题是等价的,但我不会证明。于是我上网找了一下,发现好像这就是正解,然而也没有严格的证明……总之用优先队列找编号最大,时间O(nlog(n))(像我这种从来不用STL库的人当然只能手写heap辣)
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=30010;const int maxm=100100;struct edge{ int obj; edge *Next;} e[maxm];edge *head[maxn];int cur;int pin[maxn];int ans[maxn];int Heap[maxn];int tail;int t,n,m;void Add(int x,int y){ cur++; e[cur].obj=y; e[cur].Next=head[x]; head[x]=e+cur;}void Insert(int x){ Heap[++tail]=x; int i=tail; while (i>1) { int j=i>>1; if (Heap[i]>Heap[j]) swap(Heap[i],Heap[j]); else break; i=j; }}int Get(){ int x=Heap[1]; Heap[1]=Heap[tail--]; int i=1; while (1) { int son=i; int temp=i<<1; if ( temp<=tail && Heap[temp]>Heap[son] ) son=temp; temp++; if ( temp<=tail && Heap[temp]>Heap[son] ) son=temp; if (son==i) break; swap(Heap[i],Heap[son]); i=son; } return x;}int main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); cur=-1; for (int i=1; i<=n; i++) head[i]=NULL; for (int i=1; i<=m; i++) { int a,b; scanf("%d%d",&a,&b); Add(b,a); pin[a]++; } tail=0; for (int i=1; i<=n; i++) if (!pin[i]) Insert(i); for (int i=n; i>=1; i--) { int x=Get(); for (edge *p=head[x]; p; p=p->Next) { int y=p->obj; pin[y]--; if (!pin[y]) Insert(y); } ans[i]=x; } for (int i=1; i<n; i++) printf("%d ",ans[i]); printf("%d\n",ans[n]); } return 0;}
T2:项目管理
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=525&pid=1002
题目分析:这题比第一题要简单一些吧。由于图是联通的,而且边数只比点数多10,那么我们做一遍DFS,非树边的个数顶多11条。DFS的时候我们记valson[node]表示node的儿子的权值和。修改node的权值的时候改它本身的val值,和它父亲的valson值即可。查询答案的时候将它father的val加上它的valson,再暴力查看非树边即可。
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;const int maxm=13;struct edge{ int obj; bool vis; edge *Next,*rev;} e[maxn<<1];edge *head[maxn];int cur;int cnt[maxn][maxm];int val[maxn];int fa[maxn];int vson[maxn];int t,n,m,q;void Add(int x,int y){ cur++; e[cur].obj=y; e[cur].vis=false; e[cur].rev=&e[cur+1]; e[cur].Next=head[x]; head[x]=e+cur; cur++; e[cur].obj=x; e[cur].vis=false; e[cur].rev=&e[cur-1]; e[cur].Next=head[y]; head[y]=e+cur;}void Dfs(int node){ for (edge *p=head[node]; p; p=p->Next) if (!p->vis) { p->vis=p->rev->vis=true; int son=p->obj; if (!fa[son]) fa[son]=node,Dfs(son); else cnt[node][ ++cnt[node][0] ]=son,cnt[son][ ++cnt[son][0] ]=node; }}int main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); cur=-1; for (int i=1; i<=n; i++) head[i]=NULL,fa[i]=val[i]=vson[i]=cnt[i][0]=0; for (int i=1; i<=m; i++) { int x,y; scanf("%d%d",&x,&y); Add(x,y); } fa[1]=1; Dfs(1); scanf("%d",&q); while (q--) { int cmd; scanf("%d",&cmd); if (!cmd) { int u,v; scanf("%d%d",&u,&v); val[u]+=v; if (u>1) vson[ fa[u] ]+=v; } else { int u; scanf("%d",&u); int ans=vson[u]; if (u>1) ans+=val[ fa[u] ]; for (int i=1; i<=cnt[u][0]; i++) ans+=val[ cnt[u][i] ]; printf("%d\n",ans); } } } return 0;}
T3:海岸线
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=525&pid=1003
题目分析:一道网络流好题啊。一开始我完全没想到是最小割,往贪心,DP方面想了好久。上网浏览了一下题解,知道了是最小割,再回去想,还是不知道怎么建图。后来仔细看了题解,上面说它跟《最小割模型在信息学竞赛中的应用》里面的一道例题 最优标号 Optimal Marks 很像,于是我跑过去把论文读了一遍,会做例题了,然而这题还是想不到怎么做……
我们先在网格外围一层”D”,然后这题的关键就在于最大化相邻格子中一个是陆地,一个是海洋的数量,即最小化相邻格子相同的数量。在论文中讨论了如何最小化相邻格子不同 ,但对于一个普通的图,要做到最大化不同格子,是无法建图跑网络流的。然而这里我们是网格图,我们可以对其进行黑白染色,将所有黑色的格子反转(即陆地->深海,深海->陆地,浅海->浅海)。这样就变成了论文中的情况。
这道题的难点在于往最小割方面去想,以及颜色反转。反转了之后就是一个很简单的模型,我们让每一个格子都为一个点,如果是深海,则S向其连无穷大的边,它向T连1;浅海则两个都为1;陆地则S连1,T连无穷大;相邻格子之间连一条容量为1的无向边。最后用格子数+相邻格子对数-最大流即可。
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=52;const int maxv=10010;const int maxm=1000000;const int oo=1000000000;struct edge{ int obj,cap; edge *Next,*rev;} e[maxm];edge *head[maxv];int cur;edge *nhead[maxv];int level[maxv];int que[maxv];int he,ta;int T;char s[maxn];int map[maxn][maxn];int t,n,m;int Get(int x,int y){ return x*(m+2)+y+1;}void Add(int x,int y,int xf,int yf){ cur++; e[cur].obj=y; e[cur].cap=xf; e[cur].rev=&e[cur+1]; e[cur].Next=head[x]; head[x]=e+cur; cur++; e[cur].obj=x; e[cur].cap=yf; e[cur].rev=&e[cur-1]; e[cur].Next=head[y]; head[y]=e+cur;}bool Bfs(){ for (int i=0; i<=T; i++) nhead[i]=head[i],level[i]=0; he=0,ta=1,que[1]=0,level[0]=1; while (he<ta) { int node=que[++he]; for (edge *p=head[node]; p; p=p->Next) { int son=p->obj; if ( p->cap && !level[son] ) level[son]=level[node]+1,que[++ta]=son; } } return level[T];}int Dfs(int node,int maxf){ if ( node==T || !maxf ) return maxf; int nowf=0; for (edge *&p=nhead[node]; p; p=p->Next) { int son=p->obj; if ( p->cap && level[son]==level[node]+1 ) { int d=Dfs(son, min(maxf,p->cap) ); p->cap-=d; p->rev->cap+=d; maxf-=d; nowf+=d; if (!maxf) break; } } if (maxf) level[node]=0; return nowf;}int Dinic(){ int max_flow=0; while ( Bfs() ) max_flow+=Dfs(0,oo); return max_flow;}int main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d",&t); for (int g=1; g<=t; g++) { scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) { scanf("%s",&s); for (int j=0; j<m; j++) { if (s[j]=='.') map[i][j+1]=0; if (s[j]=='E') map[i][j+1]=1; if (s[j]=='D') map[i][j+1]=2; } } for (int i=0; i<=m+1; i++) map[0][i]=map[n+1][i]=2; for (int i=1; i<=n; i++) map[i][0]=map[i][m+1]=2; for (int i=0; i<=n+1; i++) for (int j=0; j<=m+1; j++) if ( (i+j)&1 ) map[i][j]=2-map[i][j]; /*for (int i=0; i<=n+1; i++) { for (int j=0; j<=m+1; j++) printf("%d ",map[i][j]); printf("\n"); }*/ T=(n+2)*(m+2)+1; cur=-1; for (int i=0; i<=T; i++) head[i]=NULL; for (int i=0; i<=n+1; i++) for (int j=0; j<=m+1; j++) { int id=Get(i,j); if (map[i][j]==0) Add(0,id,oo,0),Add(id,T,1,0); if (map[i][j]==1) Add(0,id,1,0),Add(id,T,1,0); if (map[i][j]==2) Add(0,id,1,0),Add(id,T,oo,0); } for (int i=0; i<=n+1; i++) for (int j=0; j<=m+1; j++) { int x=Get(i,j); if (i<=n) Add(x, Get(i+1,j) ,1,1); if (j<=m) Add(x, Get(i,j+1) ,1,1); } int ans=Dinic(); ans=(n+1)*(m+2)+(n+2)*(m+1)+(n+2)*(m+2)-ans; printf("Case %d: %d\n",g,ans); } return 0;}
T4:新海岛计划
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=525&pid=1004
题目分析:计算几何不可做……
- BestCoder Round #1 解题报告
- BestCoder Round #55 解题报告
- 【解题报告】BestCoder Round #75
- 【解题报告】BestCoder Round #80
- Bestcoder round#31 解题报告
- Bestcoder round#32 解题报告
- Bestcoder round#33 解题报告
- Bestcoder round#34 解题报告
- Bestcoder round#85 解题报告
- Bestcoder round#84 解题报告
- bestcoder round#86解题报告
- BestCoder Round #2 解题报告
- BestCoder Round #10(解题报告)
- BestCoder Round #77 (div.2)解题报告
- 【解题报告】BestCoder Round #77 (div.2)
- hdu5634 BestCoder Round #73 (div.1) Rikka with Phi 解题报告
- HDU 4989 Summary BestCoder Round #8 解题报告
- BestCoder Round #13 Beautiful Palindrome Number解题报告
- The MRC database dictionary之AOA库 (age of acquisition 习得年龄)
- 学习TextInputLayout
- 2017.07.06【NOIP提高组】模拟赛B组小结
- POJ2407 Relatives
- 告别for循环!
- BestCoder Round #1 解题报告
- JZOJ4307. 【NOIP2015模拟11.3晚】喝喝喝
- The MRC database dictionary之CONC库 ( concreteness)
- 1.原理图GPIO和门电路
- 简单的(第一人称射击)FPS游戏
- hdu 1044带来的启示
- caffe源码解析
- 暑期训练7.7【JZOJ100027】表达式
- 第三讲 单片机C语言之12864液晶显示