BestCoder Round #2 解题报告
来源:互联网 发布:淘宝lolcdk是真的吗 编辑:程序博客网 时间:2024/05/20 22:00
最近感觉暑假在家好颓,效率直线下降,码代码速度慢,想题想不出。这次R2的题目也是过了很久才做完……但愿8月份到了学校情况会好些吧。
T1:TIANKENG’s restaurant
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=526&pid=1001
题目大意:给出n(n<=10000)个时间段(形式为hh:mm~hh:mm)和数字x,表示这个时间段会有x个客人来饭店就餐。每个客人需要一张椅子,问最少需要多少张椅子(一个客人离开后椅子可以立马给另一个客人坐)。不超过100组数据,保证时间段不会跨过凌晨0点。
题目分析:这题本质上就是区间加x,最后每一个数取个max。我们在开始时刻+1,在结束时刻后一分钟-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=1450;int temp[maxn];int T,n;int Read(){ int x=0; char c=getchar(); while ( c<'0' || '9'<c ) c=getchar(); while ( '0'<=c && c<='9' ) x=(x<<3)+(x<<1)+(c-'0'),c=getchar(); return x;}int Get(int x,int y){ return 60*x+y;}int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d",&T); while (T--) { memset(temp,0,sizeof(temp)); scanf("%d",&n); for (int i=1; i<=n; i++) { int x; scanf("%d",&x); int h=Read(),m=Read(); temp[ Get(h,m) ]+=x; h=Read(),m=Read(); temp[ Get(h,m) ]-=x; } int ans=0,now=0; for (int i=0; i<maxn; i++) now+=temp[i],ans=max(now,ans); printf("%d\n",ans); } return 0;}
T2:TIANKENG’s rice shop
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=526
题目大意:餐馆提供n(n<=1000)种食物。现在有m(m<=1000)个客人在hh:mm时刻来餐馆排队,每个人会点某一种食物num(num<=10)份。厨师会按照顺序给他们做饭,他会用t(t<=10)分钟做好k(k<=5)份相同类型的食物,如果供应完当前客人之后还有多余的几份,他就会将剩下这些分给已经来排队的要点该类型食物的人(靠前优先),如果还有多余的则扔掉。假设每个客人在拿到num份食物后就会离开,求每个客人的离开时刻。客人抵达的时间不会跨过凌晨0点,不超过100组数据。
题目分析:这题就是个恶心的硬模拟。我们直接开一个n*m的数组维护一下每一种食物有哪些客人点即可,时间O(Tm),其中T是数据组数。这里还有一个很坑的地方:虽然客人抵达的时间顶多是当天23:59,但是他离开的时间可能是好几天后。
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=1010;int id[maxn][maxn];int head[maxn];int tail[maxn];int Type[maxn];int Time[maxn];int num[maxn];int ans[maxn];int T,n,t,k,m;int Read(){ int x=0; char c=getchar(); while ( c<'0' || '9'<c ) c=getchar(); while ( '0'<=c && c<='9' ) x=(x<<3)+(x<<1)+(c-'0'),c=getchar(); return x;}int Get(int x,int y){ return 60*x+y;}void Print(int x){ int hh=x/60; hh%=24; int mm=x%60; if (hh<10) printf("0"); printf("%d:",hh); if (mm<10) printf("0"); printf("%d\n",mm);}int main(){ freopen("2.in","r",stdin); freopen("2.out","w",stdout); scanf("%d",&T); while (T--) { scanf("%d%d%d%d",&n,&t,&k,&m); for (int i=1; i<=n; i++) head[i]=0,tail[i]=0; for (int i=1; i<=m; i++) { int hh=Read(),mm=Read(),y; scanf("%d%d",&Type[i],&y); Time[i]=Get(hh,mm); num[i]=y; id[ Type[i] ][ ++tail[ Type[i] ] ]=i; } int nt=0; for (int i=1; i<=m; i++) if (num[i]) { nt=max(nt,Time[i]); int x=Type[i]; while (num[i]>k) num[i]-=k,nt+=t; nt+=t; int Left=k; while ( head[x]<tail[x] && Time[ id[x][ head[x]+1 ] ]<=nt-t ) { head[x]++; int y=id[x][ head[x] ]; if (num[y]<=Left) { Left-=num[y]; num[y]=0; ans[y]=nt; } else { num[y]-=Left; head[x]--; break; } } } for (int i=1; i<=m; i++) Print(ans[i]); if (T) printf("\n"); } return 0;}
T3:TIANKENG’s travel
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=526&pid=1003
题目大意:在一个平面图上给出起点,终点,以及n(n<=1000)个加油站。从一个点可以行驶到另一个和它欧几里得距离小于等于L的点,而且必须直线行驶。就是说如果两点的连线之间还有加油站,那么肯定行驶时必定会经过这个加油站。现在要求最小化从起点到终点所经过的加油站个数,不超过30组数据。
题目分析:这题我一开始没看见必须直线行驶这个条件,以为是
由于两个点中间有加油站时不能直接连边,所以我们先将点按x坐标从小到大排序,相同则按y从小到大。这样点i连向点j的边
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=1010;typedef long long LL;struct edge{ int obj; edge *Next;} e[maxn*maxn];edge *head[maxn];int cur;int level[maxn];int que[maxn];int he,ta;struct data{ int dx,dy,id;} line[maxn][maxn];struct point{ int X,Y,T;} gas[maxn];int G,n,l;bool Comp1(point x,point y){ return x.X<y.X || ( x.X==y.X && x.Y<y.Y );}bool Comp2(data x,data y){ LL temp1=x.dy; temp1*=y.dx; LL temp2=y.dy; temp2*=x.dx; bool flag=( x.dx<y.dx || ( x.dx==y.dx && x.dy<y.dy ) ); return temp1<temp2 || ( temp1==temp2 && flag );}bool Judge(int x,int y){ LL temp1=gas[x].X-gas[y].X; temp1*=temp1; LL temp2=gas[x].Y-gas[y].Y; temp2*=temp2; temp1+=temp2; temp2=l; temp2*=temp2; return temp1<=temp2; }void Add(int x,int y){ cur++; e[cur].obj=y; e[cur].Next=head[x]; head[x]=e+cur;}int Bfs(){ int s,t; for (int i=0; i<=n; i++) { level[i]=0; if (!gas[i].T) s=i; if (gas[i].T==n) t=i; } he=0,ta=1,que[1]=s; while (he<ta) { int node=que[++he]; for (edge *p=head[node]; p; p=p->Next) { int son=p->obj; if ( son && !level[son] ) { level[son]=level[node]+1; que[++ta]=son; } } } return level[t];}int main(){ freopen("3.in","r",stdin); freopen("3.out","w",stdout); scanf("%d",&G); while (G--) { scanf("%d%d",&n,&l); n++; scanf("%d%d",&gas[0].X,&gas[0].Y); scanf("%d%d",&gas[n].X,&gas[n].Y); for (int i=1; i<n; i++) scanf("%d%d",&gas[i].X,&gas[i].Y); for (int i=0; i<=n; i++) gas[i].T=i; sort(gas,gas+n+1,Comp1); cur=-1; for (int i=0; i<=n; i++) head[i]=NULL; for (int i=0; i<n; i++) { for (int j=i+1; j<=n; j++) { line[i][j-i].id=j; line[i][j-i].dx=gas[j].X-gas[i].X; line[i][j-i].dy=gas[j].Y-gas[i].Y; } sort(line[i]+1,line[i]+n-i+1,Comp2); if ( Judge(i,line[i][1].id) ) Add(i,line[i][1].id),Add(line[i][1].id,i); for (int j=2; j<=n-i; j++) { LL temp1=line[i][j].dy; temp1*=line[i][j-1].dx; LL temp2=line[i][j-1].dy; temp2*=line[i][j].dx; if ( temp1!=temp2 && Judge(i,line[i][j].id) ) Add(i,line[i][j].id),Add(line[i][j].id,i); } } int ans=Bfs(); if (ans) printf("%d\n",ans-1); else printf("impossible\n"); } return 0;}
T4:TIANKENG’s restaurant(Ⅱ)
题目传送门:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=526&pid=1004
题目大意:给出一个只包含A~H,长度不超过
题目分析:这题空间只有64M我还能说什么……当初一看这题很高兴因为这就是个SAM的裸题呀。我们把后缀自动机构出来然后就是要从根节点最快地转移到NULL并且保证字典序最小,结果空间炸得不要不要的。我伤心无奈之下忽然想起陈老师PPT里说SAM的边数不会超过状态数+字符串长度,于是我就把son[8]的指针数组改成了3*len的邻接链表(本来想写treap的,但考虑到空间开销……),时间多了个常数8而已。然而还是炸空间,后来看题解知道这就是个Hash?!
我们首先想答案会有多长。如果答案长度是7,那么长度为7的串就有
时候我对拍了一下SAM+邻接链表的程序和Hash的程序,发现没什么问题,只不过前者的常数和空间都比较大而已。极限数据Hash要3s,而SAM+邻接链表要30s……
CODE(Hash):
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=1000010;const int maxl=8;bool vis[maxn];int val[maxl];int w[maxl];int cur=0;char s[maxn];int t,slen;void Print(int x,int len){ for (int i=1; i<=len; i++) w[++cur]=x&7,x>>=3; while (cur) printf("%c",'A'+w[cur]),cur--; printf("\n");}int main(){ freopen("4.in","r",stdin); freopen("4.out","w",stdout); val[0]=1; for (int i=1; i<maxl; i++) val[i]=val[i-1]<<3; scanf("%d",&t); while (t--) { scanf("%s",&s); slen=strlen(s); for (int ans=1; ans<=maxl; ans++) { memset(vis,false,sizeof(vis)); int Hash=0; for (int i=1; i<=ans; i++) Hash=(Hash<<3)|(s[i-1]-'A'); for (int i=1; i<=slen-ans+1; i++) { vis[Hash]=true; Hash-=((s[i-1]-'A')*val[ans-1]); Hash=(Hash<<3)|(s[i+ans-1]-'A'); } bool sol=false; for (int i=0; i<val[ans]; i++) if (!vis[i]) { Print(i,ans); sol=true; break; } if (sol) break; } } return 0;}
CODE(SAM+邻接链表):
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=1000010;const int maxc=8;struct State;struct edge{ int son; State *obj; edge *Next;} e[maxn*3];int num;struct State{ int val,id,len; edge *head; State *parent;} SAM[maxn<<1];State *Root,*last;int cur;int cnt[maxn];State *Rank[maxn<<1];char s[maxn];int T,slen;State *New_state(int v){ cur++; SAM[cur].val=v; SAM[cur].head=NULL; SAM[cur].parent=NULL; return SAM+cur; }State *Get(State *P,int x){ for (edge *p=P->head; p; p=p->Next) if (p->son==x) return p->obj; return NULL;}void Add(State *P,int x,State *Q){ if (!Q) return; num++; e[num].son=x; e[num].obj=Q; e[num].Next=P->head; P->head=e+num;}void Build(int x){ int to=s[x]-'A'; x++; State *P=last,*NP=New_state(x); last=NP; while ( P && !Get(P,to) ) Add(P,to,NP),P=P->parent; if (!P) { NP->parent=Root; return; } State *Q=Get(P,to); if (P->val+1==Q->val) NP->parent=Q; else { State *NQ=New_state(P->val+1); for (int i=0; i<maxc; i++) Add(NQ,i, Get(Q,i) ); NQ->parent=Q->parent; NP->parent=Q->parent=NQ; while (P) { State *tag=Get(P,to); if (tag!=Q) break; for (edge *p=P->head; p; p=p->Next) if (p->son==to) { p->obj=NQ; break; } P=P->parent; } }}int main(){ freopen("4.in","r",stdin); freopen("4.out","w",stdout); scanf("%d",&T); while (T--) { scanf("%s",&s); slen=strlen(s); num=cur=-1; last=Root=New_state(0); for (int i=0; i<slen; i++) Build(i); for (int i=0; i<=slen; i++) cnt[i]=0; for (int i=0; i<=cur; i++) cnt[ SAM[i].val ]++; for (int i=1; i<=slen; i++) cnt[i]+=cnt[i-1]; for (int i=0; i<=cur; i++) Rank[ --cnt[ SAM[i].val ] ]=SAM+i; for (int i=cur; i>=0; i--) { Rank[i]->id=0; State *tag=Get(Rank[i],0); Rank[i]->len=(tag? tag->len:0)+1; for (int j=1; j<maxc; j++) { tag=Get(Rank[i],j); int temp=(tag? tag->len:0)+1; if (temp<Rank[i]->len) Rank[i]->len=temp,Rank[i]->id=j; } } State *P=Root; while (P) printf("%c",'A'+P->id),P=Get(P,P->id); printf("\n"); } //printf("%d\n",sizeof(e)/1024); //printf("%d\n",sizeof(SAM)/1024); return 0;}
- BestCoder Round #2 解题报告
- BestCoder Round #77 (div.2)解题报告
- 【解题报告】BestCoder Round #77 (div.2)
- 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 #1 解题报告
- BestCoder Round #10(解题报告)
- HDU 4989 Summary BestCoder Round #8 解题报告
- BestCoder Round #13 Beautiful Palindrome Number解题报告
- BestCoder Round #20 解题报告 A.B.C.
- 将已有项目下的html转为haml
- JS的逻辑思维练习
- TensorFlow学习——CIFAR-10(二)代码实现
- ios-drawrect方法解析
- Java集合类: Set、List、Map、Queue使用场景梳理
- BestCoder Round #2 解题报告
- Android获取本机局域网IP的方法
- Servlet的多线程和线程安全
- B
- Java设计模式 单列模式
- 回文串之栈
- Android自绘控件开发与性能优化实践——以录音波浪动画为例
- BZOJ 1146: [CTSC2008]网络管理Network 树链剖分 树状数组套主席树/线段树套平衡树
- jQuery选择器——基本过滤选择器