*湖南师范大学第五届大学生计算机程序设计竞赛(AKing)
【比赛链接】:http://acm.hunnu.edu.cn/online/?action=problem&type=list&courseid=132
A:跑得快计数程序
【题解】:细心点,巧妙乘2处理四舍五入,简单模拟
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <set> 7 8 #define LL long long 9 using namespace std; 10 int A[5],B[5]; 11 int main(){ 12 int t; 13 cin>>t; 14 while(t--){ 15 int N; 16 cin>>N; 17 memset(A,0,sizeof(A)); 18 memset(B,0,sizeof(B)); 19 for(int i=1;i<=N;i++){ 20 int a[5]; 21 cin>>a[1]>>a[2]>>a[3]>>a[4]; 22 int p=0; 23 for(int i=1;i<=4;i++) 24 if (a[i]>0){ 25 if (a[i]==12) B[i]=12; 26 else B[i]=(int)(a[i]*0.4+0.5); 27 }else if (a[i]==0) p=i; 28 29 B[p]=0; 30 for(int i=1;i<=4;i++){ 31 if (i!=p) B[p]+=B[i]; 32 } 33 for(int i=1;i<=4;i++){ 34 if (i!=p) B[i]=-B[i]; 35 } 36 for(int i=1;i<=4;i++) A[i]+=B[i]; 37 } 38 for(int i=1;i<=4;i++){ 39 if (i==4) cout<<A[i]<<endl;else cout<<A[i]<<" "; 40 } 41 } 42 }
B:棋盘游戏
【题解】:
【代码】:
C:区间求最值
【题解】:10^6个数字,RMQ[10^6][20]根本存不下,所以用线段树,虽然时间较慢,但是空间足够。比赛每做出这道题,说明对这两种方法没有掌握。
预处理比较精妙,建树递归O(n)算法
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 5 using namespace std; 6 7 int pris[1000005]; 8 int A[1000005]; 9 int maxv[1000005<<2]; 10 int t,n,q; 11 void init(){ 12 memset(pris,0,sizeof(pris)); 13 for(int i=1;i<=1000000;i++){ 14 for(int j=i;j<=1000000;j+=i){ 15 pris[j]++; 16 } 17 } 18 return ; 19 } 20 void builtTree(int o,int l,int r){//递归建树 21 if (l==r){ 22 maxv[o]=A[l]; 23 return;//记得return 24 } 25 int m=l+(r-l)/2; 26 builtTree(o<<1,l,m); 27 builtTree(o<<1|1,m+1,r); 28 maxv[o]=max(maxv[o<<1],maxv[o<<1|1]); 29 return ; 30 } 31 int Query(int ql,int qr,int o,int l,int r){ 32 if (ql<=l && r<=qr) return maxv[o]; 33 int m=l+(r-l)/2; 34 int ans = -1; 35 if (ql<=m) ans=max(ans,Query(ql,qr,o<<1,l,m)); 36 if (m+1<=qr) ans=max(ans,Query(ql,qr,o<<1|1,m+1,r)); 37 return ans; 38 } 39 int main(){ 40 init(); 41 scanf("%d",&t); 42 while(t--){ 43 scanf("%d",&n); 44 for(int i=1;i<=n;i++){ 45 int x; 46 scanf("%d",&x); 47 A[i]=pris[x]; 48 } 49 builtTree(1,1,n);//建树 50 scanf("%d",&q); 51 while(q--){ 52 int l,r; 53 scanf("%d%d",&l,&r); 54 int ans=Query(l,r,1,1,n); 55 printf("%d\n",ans); 56 } 57 } 58 return 0; 59 }
D:数组求和问题
【题解】:简单分析题意,直接暴力,数据量是唬人的,注意下标处理,样例有点问题
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #define LL long long 7 using namespace std; 8 int t,n,m,s,p; 9 int a[100005]; 10 11 int main(){ 12 scanf("%d",&t); 13 for(int cas=1;cas<=t;cas++){ 14 scanf("%d%d%d%d",&n,&m,&s,&p); 15 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 16 int ans=0; 17 for(int st=1;st+(m-1)*p<=n;st++){ 18 int tt=0; 19 for(int i=st;i<=st+(m-1)*p;i+=p) tt+=a[i]; 20 if (tt==s) ans++; 21 } 22 printf("case %d:%d\n",cas,ans); 23 } 24 return 0; 25 }
E:推箱子
【题解】:枚举,总共的移动方法就那么两种,特殊情况,目的地和箱子和人在一条直线上,人不能直接穿过箱子
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <set> 7 #include <math.h> 8 #define maxn 105 9 #define eps 0.0000001 10 11 #define LL long long 12 using namespace std; 13 14 int abss(int x1,int yy1,int x2,int y2){ 15 return abs(x1-x2)+abs(yy1-y2); 16 } 17 int x1,yy1,x2,y2,x3,y3; 18 int main(){ 19 while(~scanf("%d%d%d%d%d%d",&x1,&yy1,&x2,&y2,&x3,&y3)){ 20 if (x2==x3 && y2==y3){ 21 cout<<0<<endl; 22 continue; 23 } 24 int ans=99999999,m; 25 if (y2==y3){ 26 if (x2<x3){ 27 m=abss(x2-1,y2,x1,yy1)+x3-x2; 28 if (x1>x2 && yy1==y2) m+=2; 29 ans=min(ans,m); 30 } 31 if (x2>x3){ 32 m=abss(x2+1,y2,x1,yy1)+x2-x3; 33 if (x1<x2 && yy1==y2) m+=2; 34 ans=min(ans,m); 35 } 36 } 37 if (x2==x3){ 38 if (y2<y3){ 39 m=abss(x2,y2-1,x1,yy1)+y3-x2; 40 if (yy1>y2 && x1==x2) m+=2; 41 ans=min(ans,m); 42 } 43 if (y2>y3){ 44 m=abss(x2,y2+1,x1,yy1)+y2-y3; 45 if (yy1<y2 && x1==x2) m+=2; 46 ans=min(ans,m); 47 } 48 } 49 if (x2<x3 && y2<y3){ 50 m=abss(x1,yy1,x2-1,y2)+abs(x3-x2)+2+abs(y3-y2); 51 ans=min(ans,m); 52 m=abss(x1,yy1,x2,y2-1)+abs(x3-x2)+2+abs(y3-y2); 53 ans=min(ans,m); 54 } 55 if (x2<x3 && y2>y3){ 56 m=abss(x1,yy1,x2-1,y2)+abs(x3-x2)+2+abs(y3-y2); 57 ans=min(ans,m); 58 m=abss(x1,yy1,x2,y2+1)+abs(x3-x2)+2+abs(y3-y2); 59 ans=min(ans,m); 60 } 61 if (x2>x3 && y2<y3){ 62 m=abss(x1,yy1,x2+1,y2)+abs(x3-x2)+2+abs(y3-y2); 63 ans=min(ans,m); 64 m=abss(x1,yy1,x2,y2-1)+abs(x3-x2)+2+abs(y3-y2); 65 ans=min(ans,m); 66 } 67 if (x2>x3 && y2>y3){ 68 m=abss(x1,yy1,x2+1,y2)+abs(x3-x2)+2+abs(y3-y2); 69 ans=min(ans,m); 70 m=abss(x1,yy1,x2,y2+1)+abs(x3-x2)+2+abs(y3-y2); 71 ans=min(ans,m); 72 } 73 printf("%d\n",ans); 74 } 75 return 0; 76 }
F:信封问题
【题解】:
【代码】:
G:修路
【题解】:二分(答案:最长的路)+重新见图+最小生成树(判定生成了一棵完整的树)
容易错的地方:1、二分后也要判断F(L)是否可形成一颗完整的树 2、开始我忘记Merge(u,v),逗了 3、二分用for控制次数好些
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <set> 7 #include <math.h> 8 #define maxn 105 9 #define eps 0.0000001 10 11 #define LL long long 12 using namespace std; 13 int n,m,M,y; 14 15 struct E{ 16 int u,v,c,d; 17 bool operator < (const E& X)const{ 18 return c<X.c; 19 } 20 }e1[100005*2],e2[100005*2]; 21 int p[10005]; 22 void init(){ 23 for(int i=1;i<=n;i++) p[i]=i; 24 return; 25 } 26 int findx(int x){ 27 if (p[x]==x) return x;else return p[x]=findx(p[x]); 28 } 29 void merge(int x,int y){ 30 int px=findx(x); 31 int py=findx(y); 32 p[px]=py; 33 } 34 bool F(int x)//最长路 35 { 36 init(); 37 int cnt=0; 38 for(int i=0;i<M;i++){ 39 if (e1[i].d<=x) { 40 e2[cnt++]=e1[i]; 41 } 42 } 43 // cout<<"M="<<M<<endl; 44 sort(e2,e2+cnt); 45 // for(int i=0;i<cnt;i++) e2[i].print(); 46 int t=0,l=0; 47 bool vis[10005]; 48 memset(vis,0,sizeof(vis)); 49 for(int i=0;i<cnt;i++){ 50 int u=e2[i].u,v=e2[i].v,c=e2[i].c; 51 if (findx(u)==findx(v)) continue; 52 merge(u,v); 53 l+=c; 54 if (!vis[u]){ 55 vis[u]=true; 56 t++; 57 } 58 if (!vis[v]){ 59 vis[v]=true; 60 t++; 61 } 62 if (t==n) break; 63 } 64 // cout<<"t="<<t<<","<<"l="<<l<<endl; 65 if (t>=n && l<=y ) return true;else return false; 66 } 67 int main(){ 68 while(~scanf("%d%d%d",&n,&m,&y)){ 69 M=0; 70 int Maxd = -1; 71 for(int i=0;i<m;i++) { 72 int u,v,c,d; 73 scanf("%d%d%d%d",&u,&v,&c,&d); 74 if (u!=v) { 75 e1[M++]=(E){u,v,c,d}; 76 e1[M++]=(E){v,u,c,d}; 77 } 78 Maxd=max(Maxd,d); 79 } 80 if (m==0 || m<n-1) { 81 cout<<"-1"<<endl; 82 continue; 83 } 84 if (!F(Maxd)) { 85 cout<<"-1"<<endl; 86 continue; 87 } 88 int L=0,R=Maxd+1; 89 for(int t=1;t<=45;t++){ 90 int M=L+(R-L)/2; 91 if (F(M)) R=M;else L=M+1; 92 } 93 if (F(L)) cout<<L<<endl;else cout<<"-1"<<endl; 94 } 95 return 0; 96 }
H:找数游戏
【题解】:
【代码】:
I:找数字2
【题解】:10^7个数字,是我不够机智,还用神马multi-set,果断超空间,其实就是异或运算性质的运用
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
J:高校围墙
【题解】:看了很长时间才看出宿舍外围是什么意思,汗,计算凸包+多边形面积,注意1个点、2个点、多点共线的特例,就是W在这些上面了。
以后做题一定要注意这几点
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <set> 7 #include <math.h> 8 #define maxn 105 9 #define eps 0.0000001 10 11 #define LL long long 12 using namespace std; 13 struct Point 14 { 15 double x,y; 16 bool operator<(const Point& p) const//注意:按照逆时针旋转 17 { 18 if (fabs(x-p.x)<eps) return y<p.y;//注意,这里eps一定要加,不然,不能正常排序 19 else return x<p.x; 20 } 21 } P1[maxn],P2[maxn]; 22 23 typedef Point Vector; 24 25 bool operator==(Point A,Point B) 26 { 27 if ((fabs(A.x-B.x)<eps) && (fabs(A.y-B.y)<eps)) return true; 28 else return false; 29 } 30 Vector operator-(Point A,Point B)//表示A指向B 31 { 32 return (Vector){A.x-B.x,A.y-B.y}; 33 } 34 Vector operator*(Vector A,double k) 35 { 36 return (Vector){A.x*k,A.y*k}; 37 } 38 Vector operator+(Point A,Point B)//表示A指向B 39 { 40 return (Vector){B.x+A.x,B.y+A.y}; 41 } 42 double Cross(Vector A,Vector B) 43 { 44 return A.x*B.y-A.y*B.x; 45 } 46 double Area2(Point A,Point B,Point C) 47 { 48 return Cross(B-A,C-A); 49 } 50 int ConvexHull(Point *p, int n, Point* ch) //求凸包 51 { 52 sort(p, p + n);//先按照x,再按照y 53 int m = 0; 54 for(int i = 0; i < n; i++) 55 { 56 while(m > 1 && Cross(ch[m-1] - ch[m-2], p[i] - ch[m-2]) <= 0) m--; 57 ch[m++] = p[i]; 58 } 59 int k = m; 60 for(int i = n-2; i >= 0; i--) 61 { 62 while(m > k && Cross(ch[m-1] - ch[m-2], p[i] - ch[m-2]) <= 0) m--; 63 ch[m++] = p[i]; 64 } 65 if(n > 1) m--; 66 return m; 67 } 68 double solve(Point p[],int n){ 69 double ans=0; 70 for(int i=1;i<n;i++){ 71 ans+=sqrt((p[i].x-p[i-1].x)*(p[i].x-p[i-1].x)+(p[i].y-p[i-1].y)*(p[i].y-p[i-1].y)+0.0); 72 } 73 ans+=sqrt((p[n-1].x-p[0].x)*(p[n-1].x-p[0].x)+(p[n-1].y-p[0].y)*(p[n-1].y-p[0].y)+0.0); 74 return ans; 75 } 76 int t,n,cnt1,cnt2; 77 int main() 78 { 79 int cas=0; 80 while(cin>>n && n){ 81 cas++; 82 cnt1=0; 83 for(int i=0;i<n;i++) 84 { 85 LL x,y; 86 cin>>x>>y; 87 P1[cnt1++]=(Point){x+0.0,y+0.0}; 88 } 89 cnt2=ConvexHull(P1,cnt1,P2); 90 double ans=solve(P2,cnt2); 91 if (n==2) ans=sqrt((P1[n-1].x-P1[0].x)*(P1[n-1].x-P1[0].x)+(P1[n-1].y-P1[0].y)*(P1[n-1].y-P1[0].y)+0.0); 92 if (n==1) ans=0; 93 if (n>=3 && cnt2<3){//在一条直线上 94 double Max=-99999.0,Min=999999.0; 95 int p1,p2; 96 if (P1[0].x!=P1[1].x){ 97 for(int i=0;i<n;i++){ 98 if (P1[i].x<Min){ 99 Min=P1[i].x; 100 p1=i; 101 } 102 if (P1[i].x>Max){ 103 Max=P1[i].x; 104 p2=i; 105 } 106 } 107 }else{ 108 for(int i=0;i<n;i++){ 109 if (P1[i].y<Min){ 110 Min=P1[i].y; 111 p1=i; 112 } 113 if (P1[i].y>Max){ 114 Max=P1[i].y; 115 p2=i; 116 } 117 } 118 119 } 120 ans=sqrt((P1[p1].x-P1[p2].x)*(P1[p1].x-P1[p2].x)+(P1[p1].y-P1[p2].y)*(P1[p1].y-P1[p2].y)+0.0); 121 } 122 printf("Case %d: %.3lf\n",cas,ans); 123 } 124 return 0; 125 }