2015年百度之星程序设计大赛 - 初赛(1)
总结 ->过往
1001:贪心思路,每次尽量选靠后的。
因为x ,x+1, x+2 如果选了x+2,效果是比x更换的因为我后面的值是在0-k之中,只有尽量k减少的次数更少。
所以现在假设在x ,我们找y<x+k 找到最大的y;
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include<math.h> 5 #include <algorithm> 6 #include <set> 7 typedef long long ll; 8 using namespace std; 9 #define N 1023456 10 #define inf 0x3f3f3f3 11 typedef long long ll; 12 13 ll a[N]; 14 int n,m,k; 15 16 int pan(int lxl,int rr,ll x) 17 { 18 int flag=0; 19 int l=lxl,r=rr; 20 21 for (int _=1;_<=50;_++) 22 { 23 int mid=(l+r)/2; 24 if (a[mid]<=x) 25 { 26 flag=mid; 27 l=mid; 28 } 29 else r=mid; 30 } 31 return flag; 32 } 33 34 int main() 35 { 36 int T; 37 scanf("%d",&T); 38 int cas=0; 39 while (T--) 40 { 41 42 printf("Case #%d:\n",++cas); 43 scanf("%d%d%d",&n,&m,&k); 44 45 ll Max=0; 46 for (int i=1;i<=n;i++) 47 scanf("%I64d",&a[i]),Max=max(Max,a[i]); 48 sort(a+1,a+n+1); 49 int idx=pan(1,n,m); 50 if (!idx) 51 { 52 printf("madan!\n"); 53 continue; 54 } 55 ll tmp=a[idx]; 56 while (1) 57 { 58 idx=pan(idx+1,n,tmp+k); 59 if (idx==0) 60 { 61 printf("madan!\n"); 62 break; 63 } 64 tmp=a[idx]; 65 if (tmp>=Max) 66 { 67 printf("why am I so diao?\n"); 68 break; 69 } 70 k--; 71 } 72 } 73 return 0; 74 }
1002:这道题给了直接模拟做,关键点事快速找到 1->k,2->k+1,3->k+2;中是否有连续的数;
我们可以先求出区间最大值Max,Min;
首先判断Max-Min==k-1;
然后用一个数组计入数是否出现两次。用map HASH 注意map HASH预先处理一下,因为在线做毕竟多 一个log
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <cmath> #include <iostream> #include <map> using namespace std; #define N 10011 int a[N],b[N]; int n,m,nn; map<int,int>mp; int dpmin[N][17]; int dpmax[N][17]; int cnt[N]; void init() { for (int i=1;i<=n;i++) dpmin[i][0]=dpmax[i][0]=a[i]; int mm=log2(n); for (int j=1;j<=mm;j++) for (int i=1;(i+(1<<j)-1)<=n;i++) dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]), dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]); } int rmqmax(int l,int r) { int k=log2(r-l+1); return max(dpmax[l][k],dpmax[r-(1<<k)+1][k]); } int rmqmin(int l,int r) { int k=log2(r-l+1); return min(dpmin[l][k],dpmin[r-(1<<k)+1][k]); } int f[N]; int main() { scanf("%d%d",&n,&m); mp.clear(); puts("Case #1:"); for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); int nn=unique(b+1,b+n+1)-b-1; for (int i=1;i<=nn;i++) mp[b[i]]=i; for (int i=1;i<=n;i++) f[i]=mp[a[i]]; init(); while (m--) { int k; scanf("%d",&k); if (k>n) { printf("0\n"); continue; } memset(cnt,0,sizeof(cnt)); int ans=0; int chong=0; for (int i=1;i<=k;i++) { int idx =f[i]; cnt[idx]++; if (cnt[idx]==2) chong++; } int _max=rmqmax (1,k); int _min=rmqmin (1,k); if (!chong&&_max-_min==k-1) ans++; for (int i=k+1;i<=n;i++) { int x =f[i-k]; int y =f[i]; cnt[x]--; if (cnt[x]==1) chong--; cnt[y]++; if (cnt[y]==2) chong++; _max=rmqmax(i-k+1,i); _min=rmqmin(i-k+1,i); if (!chong&&_max-_min==k-1) ans++; } printf("%d\n",ans); } return 0; }
1003:水
二分答案,判断是否可行
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include<math.h> 5 #include <algorithm> 6 typedef long long ll; 7 using namespace std; 8 #define N 1023456 9 #define inf 0x3f3f3f3 10 11 int a[N],b[N]; 12 int n; 13 14 int pan(int x) 15 { 16 for (int i=1;i<=n;i++) b[i]=a[i]; 17 b[1]=b[1]-x; 18 19 for (int i=2;i<=n;i++) 20 { 21 int tmpx=b[i]-x; 22 int tmpy=b[i]+x; 23 if (b[i-1]>=tmpy) return 0; 24 b[i]=max(tmpx,b[i-1]+1); 25 } 26 return 1; 27 } 28 29 int main() 30 { 31 int T; 32 scanf("%d",&T); 33 int cas=0; 34 while (T--) 35 { 36 printf("Case #%d:\n",++cas); 37 scanf("%d",&n); 38 for (int i=1;i<=n;i++) 39 scanf("%d",&a[i]); 40 41 int l=0,r=1234567; 42 for (int _=1;_<=60;_++) 43 { 44 int mid=(l+r)/2; 45 if (pan(mid)) r=mid; 46 else l=mid; 47 } 48 printf("%d\n",r); 49 } 50 return 0; 51 }
1004:
很多平衡树,可是我并不会写treap,splay;
于是离线处理,BIT处理前缀和
具体做法:一个数记录当前管道里面有多少个数,用来求中位数;
离散所有出现的数,相对应的记录下标;
对 in 的数 树状数组更新 1,
对out 的数更新 -1;
query的数比较麻烦,我们可以二分求出最小的x sum(x)==此刻中位数的答案{说的乱}
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include<cmath> 5 #include <algorithm> 6 7 8 typedef long long ll; 9 using namespace std; 10 #define N 102345 11 #define inf 0x3f3f3f3 12 typedef long long ll; 13 int type[N],a[N],b[N],f[N]; 14 15 int n,num; 16 17 18 int lowbit(int x) 19 { 20 return x&(-x); 21 } 22 23 int sum(int x) 24 { 25 int s=0; 26 while (x) 27 { 28 s+=f[x]; 29 x-=lowbit(x); 30 } 31 return s; 32 } 33 34 void update(int x,int val) 35 { 36 while (x<=num) 37 { 38 f[x]+=val; 39 x+=lowbit(x); 40 } 41 } 42 43 44 int pan(int l,int r,int tans) 45 { 46 for (int _=1;_<=50;_++) 47 { 48 int mid=(l+r)>>1; 49 if (sum(mid)>=tans) r=mid; 50 else l=mid; 51 } 52 return r; 53 } 54 55 int main() 56 { 57 58 int cas=0; 59 while (scanf("%d",&n)!=EOF) 60 { 61 printf("Case #%d:\n",++cas); 62 memset(f,0,sizeof(f)); 63 char s[10]; 64 num=0; 65 66 for (int i=1;i<=n;i++) 67 { 68 int x; 69 scanf("%s",s); 70 if (s[0]=='i') 71 { 72 scanf("%d",&x); 73 type[i]=1; 74 a[++num]=x; 75 76 } 77 else if (s[0]=='o') 78 type[i]=3; 79 else type[i]=2; 80 } 81 82 for (int i=1;i<=num;i++) b[i]=a[i]; 83 sort(b+1,b+num+1); 84 85 int p=1; 86 int num1=1; 87 int fuck=0; 88 89 for (int i=1;i<=n;i++) 90 { 91 if (type[i]==1) 92 { 93 int idx=lower_bound(b+1,b+num+1,a[num1])-b; 94 update(idx,1); 95 num1++; 96 fuck++; 97 } 98 else if (type[i]==2) 99 { 100 int tmp=floor(fuck/2)+1; 101 102 int ans=b[pan(1,num,tmp)]; 103 printf("%d\n",ans); 104 } 105 else 106 { 107 fuck--; 108 int idx=lower_bound(b+1,b+num+1,a[p])-b; 109 update(idx,-1); 110 p++; 111 } 112 } 113 } 114 return 0; 115 }
请结合 代码
这题还有2个set的 写法,因为是求得中位数。
1005:写不出来
10056:模板,做法是 一个矩形覆盖所有出现的点。求次矩形最小面积
凸包求,加旋转卡壳(具体百度其他)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <cmath> 6 7 #define MAXN 51000 8 #define EPS 1e-10 9 10 using namespace std; 11 12 int n; 13 double minsqr; //minsqr=最小矩形面积 14 15 int dcmp(double x) 16 { 17 if(fabs(x)<EPS) return 0; 18 if(x>-EPS) return 1; 19 return -1; 20 } 21 22 struct Point 23 { 24 double x,y; 25 Point(){} 26 Point(double _x,double _y):x(_x),y(_y){} 27 void read() 28 { 29 scanf("%lf%lf",&x,&y); 30 } 31 }points[MAXN],stack[MAXN<<1],ans[10]; //ans保存最小覆盖矩形的四个顶点 32 33 Point operator-(Point a,Point b) 34 { 35 return Point(a.x-b.x,a.y-b.y); 36 } 37 38 Point operator*(Point a,double b) 39 { 40 return Point(a.x*b,a.y*b); 41 } 42 43 Point operator+(Point a,Point b) 44 { 45 return Point(a.x+b.x,a.y+b.y); 46 } 47 48 double cross(Point a,Point b,Point c) //a->b 叉积 a->c 49 { 50 return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); 51 } 52 53 double dot(Point a,Point b,Point c) //a->b 点积 b->c 54 { 55 return (b.x-a.x)*(c.x-b.x)+(b.y-a.y)*(c.y-b.y); 56 } 57 58 double dist(Point a,Point b) 59 { 60 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 61 } 62 63 int top=0; 64 65 bool cmp(Point a,Point b) 66 { 67 if(!dcmp(a.x-b.x)) return a.y<b.y; 68 return a.x<b.x; 69 } 70 71 bool operator<(Point a,Point b) 72 { 73 if(!dcmp(a.y-b.y)) return a.x<b.x; 74 return a.y<b.y; 75 } 76 77 void Graham() 78 { 79 sort(points+1,points+n+1,cmp); 80 for(int i=1;i<=n;i++) //下凸壳 81 { 82 while(top>=2&&dcmp(cross(stack[top-1],stack[top],points[i])<=0)) top--; 83 stack[++top]=points[i]; 84 } 85 int tmp=top; 86 for(int i=n-1;i>=1;i--) //上凸壳 87 { 88 while(top>=tmp+1&&dcmp(cross(stack[top-1],stack[top],points[i])<=0)) top--; 89 stack[++top]=points[i]; 90 } 91 top--; //栈顶显然是points[1],重复了一次,将重复的丢掉 92 } 93 94 void rotcalip() //旋转卡壳 95 { 96 int left=1,right=1,up=1; //左、右、上三个点 97 for(int i=1;i<=top;i++) 98 { 99 while(dcmp(cross(stack[up+1],stack[i],stack[i+1])-cross(stack[up],stack[i],stack[i+1]))>=0) up=up%top+1; 100 while(dcmp(dot(stack[right+1],stack[i+1],stack[i])-dot(stack[right],stack[i+1],stack[i]))>=0) right=right%top+1; 101 if(i==1) left=right; 102 while(dcmp(dot(stack[left+1],stack[i],stack[i+1])-dot(stack[left],stack[i],stack[i+1]))>=0) left=left%top+1; 103 double L=dist(stack[i],stack[i+1]); //L=点i到i+1的距离 104 double H=cross(stack[i+1],stack[up],stack[i])/L; //H是矩形的高 105 double bottom=(fabs(dot(stack[i],stack[i+1],stack[left])/L)+fabs(dot(stack[i],stack[i+1],stack[right])/L)); 106 double nowsqr=bottom*H; 107 if(nowsqr<minsqr) //这个解比当前答案更优 108 { 109 minsqr=nowsqr; 110 ans[0]=stack[i]+(stack[i+1]-stack[i])*((fabs(dot(stack[i],stack[i+1],stack[right]))/L+L)/L); 111 ans[1]=ans[0]+(stack[right]-ans[0])*(H/dist(stack[right],ans[0])); 112 ans[2]=ans[1]+(stack[up]-ans[1])*(bottom/dist(stack[up],ans[1])); 113 ans[3]=ans[2]+(stack[left]-ans[2])*(H/dist(stack[left],ans[2])); 114 } 115 } 116 } 117 void init() 118 { 119 top=0; 120 } 121 122 int main() 123 { 124 int cas; 125 scanf("%d",&cas); 126 for (int _=1;_<=cas;_++) 127 { 128 init(); 129 printf("Case #%d:\n",_); 130 minsqr=1e12; 131 scanf("%d",&n); 132 for(int i=1;i<=n*4;i++) 133 points[i].read(); 134 n=n*4; 135 Graham(); 136 rotcalip(); 137 int ans=round(minsqr); 138 printf("%d\n",ans); 139 } 140 return 0; 141 }
随性Code