20160721考试总结

来源:互联网 发布:淘宝卖家怎么设置运费 编辑:程序博客网 时间:2024/06/05 02:21

第一题:生气的奶牛

题目描述

在数轴x上摆放有n(2<=n<=50000)捆干草堆,没有任何两堆在同样的位置,所有的位置均为整数。你可以用弹弓射击射击数轴上的任意地点。如果你用弹弓以R的力度射击x处,那么该处会发生爆炸,爆炸的范围是以R为半径的圆形区域,所以它会使得[x-R,x+R]的所有干草堆同时发生爆炸。这些干草堆的爆炸半径是R-1。它们又会触发连锁反应,第三轮的爆炸的半径为R-2,依次递减。请选择最小的力度射击,使得所有的干草堆全部爆炸。

输入

第一行包含N。接下来N个整数,表示干草堆的位置。所有位置在[0,1000000000]内。

输出

输出最小的力度R,使得所有的干草堆发生爆炸。四舍五入保留一位小数。

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

58 10 3 11 1

样例输出

3.0

提示

样例解释:

如果以力度3射击坐标5,则坐标3,坐标8处的干草堆会发生爆炸,然后又会引爆坐标1和坐标10的干草堆,最后引爆坐标11处的干草堆。

题解:

二分半径R,难点在于如何用O(n)的时间进行check,先从左往右假设刚好被波及的情况下最多能被波及到哪里,在从右往左来一遍,判断能否把所有草堆波及到。

#include<iostream>#include<cstdio>#include<algorithm>#include<ctime>using namespace std;const int N=50000+10;const double inf=1e24;const double eps=1e-2;int n;double p,pos[N],d[N];bool check(double R){double rmost,lmost;d[1]=0;int j;for(int i=1;i<=n;i=j){if(i==n) return 1;for(j=i+1;pos[j]-pos[i]<=d[i]+1&&j<=n;j++);if(j!=i+1) j--;if(pos[j]-pos[i]>R-1){rmost=pos[i]+R;break ;}d[j]=max(d[i]+1,pos[j]-pos[i]);if(d[i]>R-2&&d[i]<=R-1){rmost=pos[i]+R;break ;}}d[n]=0;for(int i=n;i>=1;i=j){if(i==1) return 1;for(j=i-1;pos[i]-pos[j]<=d[i]+1&&j>=1;j--);if(j!=i-1) j++;if(pos[i]-pos[j]>R-1){lmost=pos[i]-R;break ;}d[j]=max(d[i]+1,pos[i]-pos[j]);if(d[i]>R-2&&d[i]<=R-1){lmost=pos[i]-R;break ;}}return rmost>=lmost;}double devide(double l,double r){if(r-l<=eps) return l;double mid=(l+r)/2.0;if(check(mid)) return devide(l,mid);elsereturn devide(mid,r);}int main(){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lf",&pos[i]);sort(pos+1,pos+n+1);printf("%.1lf\n",devide(0,(pos[n]-pos[1])/2));}
分数:20

分析:一直在考虑二分+贪心,但想了很多贪心思路又找到了反例,最后完全在乱搞/(ㄒoㄒ)/~~

第二题:无线电通信

题目描述

农夫约翰和奶牛贝西要去寻找丢失的奶牛,为了彼此能联系对方,他们带着无线电通讯设备。不幸的是电池快没有电了。所以它们要尽量节省电能。农夫从位置(fx,fy)出发,一共走N步,贝西从位置(bx,by)出发,一共走M步。农夫的路线是由一个长度为N的字符串限制,字符串只出现’N’或’E’或’S’或’W’中,表示东南西北四个方向。农夫每一单位时间可以选择不动,或者按照限制走出一步。奶牛贝西也是如此。但他们必须走完这个字符串。无线电设备每一单位时间消耗的电量等于他们的距离的平方。请问,他们走到终点,最少消耗多少电量?

输入

第一行两个整数n,m(1<=n,m<=1000),第二行为fx,fy表示农夫的起始位置,第三行为bx,by,表示贝西的起始位置。
接下来有两个字符串,第一个字符串表示农夫的路线,第二个字符串表示贝西的路线。
他们的坐标总是在(0<=x,y<=1000)。北是y的正方向,东为x的正方向。

输出

输出一个整数,表示最少消耗的电量。

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

2 73 05 0NNNWWWWWN

样例输出

28
题解:dp[i][j]表示农夫走到i,贝西走到j的最小电量,思路和方程式都和最长公子序列很像。dp[i][j]=min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+dis(i->j)^2.

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=1000+10;const int inf=0x3f3f3f3f;int n,m,dp[N][N];int posf[N][2],posb[N][2];char strf[N],strb[N];int d[N][2];int dis(int i,int j){return (posf[i][0]-posb[j][0])*(posf[i][0]-posb[j][0])+(posf[i][1]-posb[j][1])*(posf[i][1]-posb[j][1]);}int main(){d['N'][0]=0,d['N'][1]=1;d['S'][0]=0,d['S'][1]=-1;d['W'][0]=-1,d['W'][1]=0;d['E'][0]=1,d['E'][1]=0;scanf("%d %d",&n,&m);scanf("%d %d",&posf[0][0],&posf[0][1]);scanf("%d %d",&posb[0][0],&posb[0][1]);scanf("%s%s",strf+1,strb+1);int len=strlen(strf+1);for(int i=1;i<=len;i++){posf[i][0]=posf[i-1][0]+d[(int)strf[i]][0];posf[i][1]=posf[i-1][1]+d[(int)strf[i]][1];}len=strlen(strb+1);for(int i=1;i<=len;i++){posb[i][0]=posb[i-1][0]+d[(int)strb[i]][0];posb[i][1]=posb[i-1][1]+d[(int)strb[i]][1];}for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)if(i||j){dp[i][j]=inf;if(i&&j) dp[i][j]=min(dp[i][j],dp[i-1][j-1]+dis(i,j));if(i) dp[i][j]=min(dp[i][j],dp[i-1][j]+dis(i,j));if(j) dp[i][j]=min(dp[i][j],dp[i][j-1]+dis(i,j));}printf("%d\n",dp[n][m]);}

成绩:100~\(≧▽≦)/~

分析:明明很水的一道题,理解题意时卡了很久,耽误了很多时间,但幸好最后还是A了(=^ ^=)。


第三题:关灯

题目描述

谷仓是一个简单的多边形。它的每一条边或平行于x轴,或平行于y轴。从任意一个点沿顺时针方向走,横边和纵边是交替出现的。多边形一共有n个点,编号为1到n。其中1号点为出口。奶牛贝西已经完全记住了谷仓的地图。它从某一个点出发,只能沿着边界走,在开灯的情况,它能很快知道怎么走才能更快到达出口。可是有一天,灯熄灭了。它一下慌了神,然后它忘了自己在哪个点了。但是幸运的是它仍然记得整个谷仓的地图,而且它能够凭触觉知道当前点的内角有多大,它也能感觉到当前点是不是出口,而且经过一条边后也能精确地计算出该边的长度。现在,为了寻找出口,它决定采取这样的策略:沿着顺时针方向继续走下去,直到它能够判断出自己的位置,然后再选择距离最短的方向(顺时针或逆时针)走到出口。求最坏的情况下,贝西走到出口要比灯没坏的情况下多花多少时间。

输入

第一行包含N(4<=N<=200),接下来N行每行包含两个整数,表示多边形的n个顶点(xi,yi),按顺时针的方向给出。这些点的范围均在[-100000,100000]

输出

输出贝西按照上述策略在最坏情况下比正常情况下要多花的时间。

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

40 00 101 101 0

样例输出

2

提示

贝西如果在出口处,肯定可以感知到,这绝对不会是最坏情况。现在考虑它在其他3个点时的情形:它当前可以感知到内角的大小。但因为内角都是90度所以他无法确定自己位置于是它按照既定的策略顺时针走

1. 如果它在开始在点2,它需要走到点3,此时,它知道自己在哪里了。于是它找最短的路径,不管哪边,都是11.所以,它一共需要走12个单位。如果是开灯的情况下,只需要走10个单位。所以,它要多走两个单位。

2. 如果它在点3,它要走11个单位。开灯的情况下也要走11个单位。

3. 如果它在点4,它要走1个单位。开灯的情况下也要走1个单位。

于是最坏的情况下它要多走两个单位
题解:记录每一种路径的情况(长度+角度),hash或map判断是否唯一来确定奶牛走到当前点时是否知道自己在哪里。难点在判断角度,因为点是由顺时针顺序给出,所以用连续的三个点向量叉乘就可以判断出当前内角(90度或270度)注意出口特判。

#include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<map>#include<ctime>using namespace std;const int N=200+10;pair<int,int> point[N];map<vector<pair<int,bool> >,int > hash; vector<pair<int,bool> > way;int n,sum[N],Min[N];bool flag[N][N],angle[N];int dis(int i,int j){if(point[i].first==point[j].first)return abs(point[i].second-point[j].second);elsereturn abs(point[i].first-point[j].first);}int lst(int now){return now==1?n:now-1;}int nxt(int now){return now==n?1:now+1;}bool check(int a,int b,int c){pair<int,int> x1=make_pair(point[b].first-point[a].first,point[b].second-point[a].second);pair<int,int> x2=make_pair(point[c].first-point[b].first,point[c].second-point[b].second);return x1.first*x2.second-x1.second*x2.first<0;}void print(vector<pair<int,bool> > q){int siz=q.size();for(int i=0;i<siz;i++)printf("%d %d\n",q[i].first,q[i].second);puts("------------------");}int main(){//freopen("1.in","r",stdin);//freopen("1.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d %d",&point[i].first,&point[i].second);if(i>1) sum[i]=sum[i-1]+dis(i-1,i);}for(int i=1;i<=n;i++){Min[i]=min(sum[i],sum[n]-sum[i]+dis(1,n));angle[i]=check(lst(i),i,nxt(i));}//puts("------------------");int ans=0;for(int i=2;i<=n;i++){way.clear();way.push_back(make_pair(0,angle[i]));for(int j=i;j<n;j++){way.push_back(make_pair(dis(j,nxt(j)),angle[nxt(j)]));//printf("from %d to %d:\n",i,j);//print(way);hash[way]++;}}//puts("***************");for(int i=2;i<=n;i++){way.clear();way.push_back(make_pair(0,angle[i]));for(int j=i;j<n;j++){way.push_back(make_pair(dis(j,nxt(j)),angle[nxt(j)]));//printf("from %d to %d\n",i,j);//print(way);if(hash[way]==1){ans=max(ans,sum[nxt(j)]-sum[i]+Min[nxt(j)]-Min[i]);break ;}//else printf("----%d\n",hash[way]);}}printf("%d\n",ans);}/*60 00 11 11 22 22 0*//*80 00 11 11 22 22 13 13 0*/
成绩:20   o(>﹏<)o

分析:在理解顺时针时想太复杂,用n^4算角度qnq,TLE。。O__O"…。主要还是时间太紧根本没细想。

第四题:分梨子

题目描述

  Finley家的院子里有棵梨树,最近收获了许多梨子。于是,Finley决定挑出一些梨子,分给幼稚园的宝宝们。可是梨子大小味道都不太一样,一定要尽量挑选那些差不多的梨子分给孩子们,那些分到小梨子的宝宝才不会哭闹。   每个梨子都具有两个属性值,Ai和Bi,本别表示梨子的大小和甜度情况。假设在选出的梨子中,两个属性的最小值分别是A0和B0。只要对于所有被选出的梨子i,都满足C1*(Ai-A0)+C2*(Bi-B0)≤C3(其中,C1、C2和C3都是已知的常数),就可以认为这些梨子是相差不多的,可以用来分给小朋友们。   那么,作为幼稚园园长的你,能算出最多可以挑选出多少个梨子吗?

输入

第一行一个整数N(1≤N≤2000),表示梨子的总个数。 第二行三个正整数,依次为C1,C2和C3(C1,C2≤2000,C3≤10^9)。 接下来的N行,每行两个整数。第i行的两个整数依次为Ai和Bi。

输出

只有一个整数,表示最多可以选出的梨子个数。

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

32 3 63 21 12 1

样例输出

2

题解:n^3枚举a0和b0再每个点check能否被选中,把每个梨子看成一个点,A和B分别为x和y坐标,然后就可以线性规划,枚举Ai,从下往上枚举Bi,需要统计的就是直角边为C3的直角三角形内有多少个点。这个代码参照了标程。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int N=2000+10;struct node{int pos,val;bool operator < (const node &x)const{return val<x.val;}}Y[N],K[N];int n,A[N],B[N],dp[N];int c1,c2,c3;int main(){scanf("%d",&n);scanf("%d %d %d",&c1,&c2,&c3);for(int i=1;i<=n;i++){scanf("%d %d",&A[i],&B[i]);Y[i].pos=K[i].pos=i;K[i].val=A[i]*c1+B[i]*c2-c3;Y[i].val=B[i];}sort(K+1,K+n+1),sort(Y+1,Y+n+1);int ans=0;for(int i=1;i<=n;i++){memset(dp,0,sizeof dp);int k=0,sum=0;for(int j=1;j<=n;j++){while(k<=n&&K[k].val<=A[i]*c1+Y[j].val*c2){if(A[K[k].pos]>=A[i]&&B[K[k].pos]>=Y[j].val)                    sum++,dp[B[K[k].pos]]++;               k++;}sum-=dp[Y[j-1].val],dp[Y[j-1].val]=0;            ans=max(ans,sum);}}printf("%d\n",ans);}

成绩:20

分析:这道题确实比较难,完全没有想出正解,考试时想简单了,甚至n^3的算法都没写出来还是很遗憾的TAT。


总结:考得挺炸的,与其他人的差距基本就是第一题o(╯□╰)o,在考试时第一题卡了很久,但60分的贪心都没有想出来/(ㄒoㄒ)/~~,耽误的很多时间,其实当时应该跳过过一会在回来看可能会好一些,毕竟现在想起来当时完全陷入错误思路无法自拔O__O"…,然后就是二三题在理解题意上有点尴尬%>_<%,第四题完全没有时间,如果冷静一下的话,n^3的算法应该是没有什么问题的。可能还是太久没有考试了,实际考试和原题检测差距还是很大的,发挥和状态还有策略上都有一定的失误,但卡在第一题还是自己太水了QnQ。。233333333333