比赛地址:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17831#overview
第1题:一个类似论坛的模拟,要你给出服务器发出的字符长度,可能加用户,减用户,每次都是群发
分析:一开始还想模拟用户增减,后来发现根本不用,因为操作都是合法的,所以只要开一个变量统计总人数,每次发出长度就能计算了
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; char s[111]; int i,ans,num; int main() { num=ans=0; while(gets(s)) { if(s[0]=='+')++num; else if(s[0]=='-')--num; else { for(i=0;i<strlen(s);++i) if(s[i]==':')break; ans+=(strlen(s)-i-1)*num; } } printf("%d\n",ans); return 0; }
第2题:给你一段文章,要你对它做居中排序。。。
分析:当一个字符串无法居中,也就是左右长度不一,交替靠左靠右排。。。纯粹靠眼力啊,我这样老眼昏花的,注定悲剧。。。
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int mm=1111; char s[mm][mm]; int i,n,m,ml,w,a,b; void outc(int m,char c) { while(m--)printf("%c",c); } int main() { n=0; while(gets(s[n]))++n; for(ml=i=0;i<n;++i) ml=max(ml,(int)strlen(s[i])); outc(ml+2,'*'); puts(""); for(w=i=0;i<n;++i) { printf("*"); m=ml-strlen(s[i]); a=m/2; if(m&1)a+=w,w=w^1; b=m-a; outc(a,' '); printf("%s",s[i]); outc(b,' '); printf("*\n"); } outc(ml+2,'*'); puts(""); return 0; }
第3题:要求最长的合法括号对的长度,还有他的个数
分析:由于这个最长的肯定在某段区间里,那么我们把能匹配的括号都删掉,剩下那些没匹配的括号的下标,正好可以用来计算匹配掉的长度,直接统计就行了,具体用一个栈结构来搞
代码:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int mm=2222222; int p[mm]; char s[mm],q[mm]; int i,j,m,n,ans,sum; int main() { while(~scanf("%s",s)) { n=strlen(s); p[m=0]=-1; for(i=0;i<n;++i) if(!m||q[m]==')'||s[i]==q[m])q[++m]=s[i],p[m]=i; else --m; p[++m]=n; ans=-n; for(i=0;i<m;++i) if(p[i+1]-p[i]-1>ans)ans=p[i+1]-p[i]-1,sum=1; else if(p[i+1]-p[i]-1==ans)++sum; if(ans>0)printf("%d %d\n",ans,sum); else puts("0 1"); } return 0; }
第4题:给你一条公路,在路上的一点限制速度,要求到那点的速度小于w,给出所有信息,求最快多久通过整条公路
分析:物理题一个,比赛时忘记写一个情况挂了(明明当时考虑了,就是忘写上去),首先分两种情况,一种是车怎么加速,到限速点的速度都不会超速,那么直接加速开就行,别忘记速度上限,第二种情况比较麻烦,以为一直加速会导致超速,那么在减速点之前,我们先加速到w,然后剩下的那段路程,先加速,再减速到w即可(别忘记超过上限v就不能加速了,我因此wa了),这个加速和减速的距离是一样的,所以可以把路程除二方便计算,当然,如果会超过v,那就更好计算了,这些都得考虑,最后剩下l-d的距离,直接加速到底,同样考虑上限v后匀速。。。。总之烦人的题,这次考虑的还算清晰,就是写代码时忘记了,哎= =
代码:
#include<cmath> #include<cstdio> #include<iostream> using namespace std; double a,v,w,l,d,t,t1; double fun(double a,double b,double c) { double del=b*b-4*a*c; if(del<0)return 0; return (-b+sqrt(del))/(2*a); } int main() { while(~scanf("%lf%lf%lf%lf%lf",&a,&v,&l,&d,&w)) { if(v<=w||(0.5*w*w>=a*d)) { t=v/a; if(0.5*v*t>=l)printf("%.12lf\n",sqrt(2*l/a)); else { t=t+(l-0.5*v*t)/v; printf("%.12lf\n",t); } } else { t=(v-w)/a; if(0.5*v*v/a+v*t-0.5*a*t*t>=d) { t=w/a; t=t+fun(a,2*w,0.5*a*t*t-d)*2; } else t=v/a+(v-w)/a+(d-(0.5*v*v/a+v*t-0.5*a*t*t))/v; t1=(v-w)/a; if(w*t1+0.5*a*t1*t1+d>=l)t=t+fun(0.5*a,w,d-l); else { l=l-(w*t1+0.5*a*t1*t1+d); t=t+t1+l/v; } printf("%.12lf\n",t); } } return 0; }
第5题:给出一个环状的n座山,问有多少对山相互可见,要求在他们之间的山都不高于他们
分析:我们从左向右扫描,当前一座山比当前的山低时,他一定不能被后面的山看到,所与把他从队列中删除是正确的,删除的时候同时答案加1,直到前面没有山比当前山低,然后继续增加山,那么边界的情况怎么处理,而且它不是能向两边观望吗?直接选取最高的山当作第一座山和最后一座山即可,最后一座山删除时得留下一座,以免重复计算,这样就行了吗?我就这样wa了一次,其实还有一样高的山,这些得特殊计算。。。具体就是利用n*(n-1)/2这个公式来算,还有答案会超int得注意下
代码:
#include<cstdio> #include<iostream> using namespace std; const int mm=1111111; int a[mm],q[mm]; int i,j,l,n; long long r,ans; int main() { while(~scanf("%d",&n)) { for(l=i=0;i<n;++i) { scanf("%d",&a[i]); if(a[i]>a[l])l=i; } q[ans=r=0]=a[l]; for(i=l+1;(i%n)!=l;++i) { j=1; while(r&&a[i%n]>q[r]) { ans+=j; if(q[r-1]==q[r])++j; else j=1; --r; } q[++r]=a[i%n]; ++ans; } j=1; while(r>1&&a[l]>q[r]) { ans+=j; if(q[r-1]==q[r])++j; else j=1; --r; } if(r>1) { ++ans; ans=ans+r*(r+1)/2-r-1; } cout<<ans<<endl; } return 0; }