2017-10-04清北模拟赛
T1 财富(treasure)
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK有n个小伙伴。每个小伙伴有一个身高hi。
这个游戏是这样的,LYK生活的环境是以身高为美的环境,因此在这里的每个人都羡慕比自己身高高的人,而每个人都有一个属性ai表示它对身高的羡慕值。
这n个小伙伴站成一列,我们用hi来表示它的身高,用ai来表示它的财富。
每个人向它的两边望去,在左边找到一个最近的比自己高的人,然后将ai朵玫瑰给那个人,在右边也找到一个最近的比自己高的人,再将ai朵玫瑰给那个人。当然如果没有比自己身高高的人就不需要赠送别人玫瑰了。也就是说一个人会给0,1,2个人玫瑰(这取决于两边是否有比自己高的人)。
每个人都会得到若干朵玫瑰(可能是0朵),LYK想知道得了最多的玫瑰的那个人得了多少玫瑰。(然后嫁给他>3<)
输入格式(treasure.in)
第一行一个数n表示有n个人。
接下来n行,每行两个数hi,ai。
输出格式(treasure.out)
一个数表示答案。
输入样例
3
4 7
3 5
6 10
输出样例
12
样例解释
第一个人会收到5朵玫瑰,第二个没人送他玫瑰,第三个人会收到12朵玫瑰。
数据范围
对于50%的数据n<=1000,hi<=1000000000。
对于另外20%的数据n<=50000,hi<=10。
对于100%的数据1<=n<=50000,1<=hi<=1000000000。1<=ai<=10000。
1 /* 2 o(n)每个点向左找一个最近的且比它大的, 3 o(n)每个点向右找一个最近的且比他大的 4 f[i]第i个人收到的玫瑰数 5 Stack[i]在单调的数列中第i个位置是n个人中的哪个人 6 求最靠近它且比它高的那个位置是哪个 7 O(n) 8 */ 9 #include <cstdio> 10 11 #define LL long long 12 inline void read(LL &x) 13 { 14 x=0; register char ch=getchar(); 15 for(; ch>'9'||ch<'0'; ) ch=getchar(); 16 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 17 } 18 const int N(50005); 19 LL n,h[N],v[N],f[N],ans; 20 int Stack[N],top; 21 22 int Presist() 23 { 24 // freopen("treasure.in","r",stdin); 25 // freopen("treasure.out","w",stdout); 26 read(n); 27 for(int i=1; i<=n; ++i) 28 read(h[i]),read(v[i]); 29 for(int i=1; i<=n; ++i) 30 { 31 for(; top&&h[i]>=h[Stack[top]]; ) top--; 32 //=注意 33 f[Stack[top]]+=v[i]; 34 Stack[++top]=i; 35 } top=0; 36 for(int i=n; i>=1; --i) 37 { 38 for(; top&&h[i]>=h[Stack[top]]; ) top--; 39 f[Stack[top]]+=v[i]; 40 Stack[++top]=i; 41 } 42 for(int i=1; i<=n; ++i) 43 ans=ans>f[i]?ans:f[i]; 44 printf("%I64d",ans); 45 return 0; 46 } 47 48 int Aptal=Presist(); 49 int main(int argc,char**argv){;}
T2 正方形(square)
Time Limit:1000ms Memory Limit:128MB
题目描述
在一个10000*10000的二维平面上,有n颗糖果。
LYK喜欢吃糖果!并且它给自己立了规定,一定要吃其中的至少C颗糖果!
事与愿违,LYK只被允许圈出一个正方形,它只能吃在正方形里面的糖果。并且它需要支付正方形边长的价钱。
LYK为了满足自己的求食欲,它不得不花钱来圈一个正方形,但它想花的钱尽可能少,你能帮帮它吗?
输入格式(square.in)
第一行两个数C和n。
接下来n行,每行两个数xi,yi表示糖果的坐标。
输出格式(square.out)
一个数表示答案。
输入样例
3 4
1 2
2 1
4 1
5 2
输出样例
4
样例解释
选择左上角在(1,1),右下角在(4,4)的正方形,边长为4。
数据范围
对于30%的数据n<=10。
对于50%的数据n<=50。
对于80%的数据n<=300。
对于100%的数据n<=1000。1<=xi,yi<=10000。
1 /* 2 求最小的代价,考虑二分(logmaxlen) 3 发现数据范围支持n^2logmaxlen的复杂度 4 现将所求正方形看做是一个无限高的矩形, 5 O(n)枚举一个右端点,确定出左端点后, 6 再O(n)判断在规定的高度内能否得到C个糖果 7 */ 8 #include <algorithm> 9 #include <cstdio> 10 11 inline void read(int &x) 12 { 13 x=0; register char ch=getchar(); 14 for(; ch>'9'||ch<'0'; ) ch=getchar(); 15 for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 16 } 17 const int N(1e3+5); 18 19 struct Pos { 20 int x,y; 21 bool operator < (const Pos&a)const 22 { 23 return x<a.x; 24 } 25 }pos[N]; 26 27 int n,c,L,R,Mid,ans,cnt,tmp[N]; 28 bool cmp(int a,int b) { return a<b; } 29 inline bool judge(int l,int r) 30 { 31 if(r-l+1<c) return false; 32 cnt=0; 33 for(int i=l; i<=r; ++i) 34 tmp[++cnt]=pos[i].y; 35 std::sort(tmp+1,tmp+cnt+1,cmp); 36 for(int i=c; i<=cnt; ++i) 37 if(tmp[i]-tmp[i-c+1]<=Mid) return 1; 38 return false; 39 } 40 inline bool check(int x) 41 { 42 int l=1,r=1; 43 for(; r<=n; ++r) 44 if(pos[r].x-pos[l].x>x) 45 { 46 if(judge(l,r-1)) return true; 47 for(; pos[r].x-pos[l].x>x; ) l++; 48 } 49 return judge(l,n); 50 } 51 52 int Presist() 53 { 54 read(c),read(n); 55 for(int i=1; i<=n; ++i) 56 read(pos[i].x),read(pos[i].y); 57 std::sort(pos+1,pos+n+1); 58 for(R=10000; L<=R; ) 59 { 60 Mid=L+R>>1; 61 if(check(Mid)) 62 { 63 R=Mid-1; 64 ans=Mid+1; 65 } 66 else L=Mid+1; 67 } 68 printf("%d\n",ans); 69 return 0; 70 } 71 72 int Aptal=Presist(); 73 int main(int argc,char**argv){;}
T3 追逐(chase)
Time Limit:1000ms Memory Limit:128MB
题目描述
这次,LYK以一个上帝视角在看豹子赛跑。
在一条无线长的跑道上,有n只豹子站在原点。第i只豹子将在第ti个时刻开始奔跑,它的速度是vi/时刻。
因此在不同的时刻,这n只豹子可能在不同的位置,并且它们两两之间的距离也将发生变化。
LYK觉得眼光八方太累了,因此它想找这么一个时刻,使得最远的两只豹子的距离尽可能近,当然这不能是第0时刻或者第0.01时刻。它想知道的是最迟出发的豹子出发的那一刻开始,离得最远的两只豹子在距离最小的时候这个距离是多少。
当然这个时刻不仅仅可能发生在整数时刻,也就是说可能在1.2345时刻这个距离最小。
输入格式(chase.in)
第一行一个数n。
接下来n行,每行两个数分别是ti和vi。
输出格式(chase.out)
输出一个数表示答案,你只需保留小数点后两位有效数字就可以了。
输入样例
3
1 4
2 5
3 7
输出样例
0.33
样例解释
在第5+2/3这个时刻,第一只豹子在18+2/3这个位置,第二只豹子在18+1/3这个位置,第三只豹子在18+2/3这个位置,最远的两只豹子相距1/3的距离,因此答案是0.33。
数据范围
对于20%的数据n=2。
对于20%的数据n=3
对于60%的数据n<=100。
对于80%的数据n<=1000。
对于100%的数据n<=100000,1<=vi,ti<=100000。
二分+计算几何。
1 /* 2 左边为1的情况下,右边是什么 3 4 随着左边向右移动,右边也一定向右移动。 5 6 左边至多移动n次,右边也至多移动n次,总共2n次。 O(n),这个宽t至少是多少 7 8 假设绿色的最短的那根不在交点处取到。 9 t>mid 不可行 t<=mid 可行 10 11 求出所有交点,然后再求每只豹子在这个交点的那个时刻的位置,更新答案。 12 */ 13 #include<algorithm> 14 #include<iostream> 15 #include<cstring> 16 #include<cstdlib> 17 #include<cstdio> 18 #include<cmath> 19 20 using namespace std; 21 22 const long double INF=(long double)1000000000*10; 23 const int N(1e5+5); 24 long double L,R,mid,ans,hh[N]; 25 int r,rr,i,n,MAX,X,Y,cnt,vv[N],vv2[N]; 26 struct node2 { 27 int t; 28 long double l; 29 } s[N<<1],S[N<<1]; 30 struct node { 31 int t,v; 32 } t[N]; 33 int cmp(node i,node j) 34 { 35 return i.v<j.v || i.v==j.v && i.t>j.t; 36 } 37 struct Node 38 { 39 long double x; 40 int y,z; 41 } p[N<<1]; 42 int CMP(Node i,Node j) 43 { 44 return i.x<j.x; 45 } 46 long double work(int x,long double y) 47 { 48 return (long double)t[x].v*y-hh[x]; 49 } 50 int main() 51 { 52 freopen("chase.in","r",stdin); 53 freopen("chase.out","w",stdout); 54 while (1) 55 { 56 scanf("%d",&n); 57 // if (n==0) return 0; 58 MAX=0; 59 for (i=1; i<=n; i++) 60 { 61 scanf("%d%d",&t[i].t,&t[i].v); 62 MAX=max(MAX,t[i].t); 63 } 64 sort(t+1,t+n+1,cmp); 65 int MIN=t[n].t; 66 for (i=n-1; i>=2; i--) 67 { 68 if (t[i].t>MIN) vv[i]=1; 69 else 70 MIN=t[i].t,vv[i]=0; 71 } 72 for (i=1; i<=n; i++) hh[i]=(long double)t[i].t*t[i].v; 73 r=1; 74 s[1].l=MAX; 75 s[1].t=1; 76 s[2].l=INF; 77 vv[n]=0; 78 for (i=2; i<=n; i++) 79 if (!vv[i]) 80 { 81 while (r && work(i,s[r].l)>=work(s[r].t,s[r].l)) r--; 82 if (!r) 83 { 84 r=1; 85 s[1].l=MAX; 86 s[1].t=i; 87 continue; 88 } 89 L=s[r].l; 90 R=s[r+1].l; 91 mid=(L+R)/2.0; 92 for (int I=1; I<=80; I++) 93 { 94 if (work(i,mid)>=work(s[r].t,mid)) 95 { 96 R=mid; 97 mid=(L+R)/2.0; 98 } 99 else 100 { 101 L=mid; 102 mid=(L+R)/2.0; 103 } 104 } 105 s[++r].l=mid; 106 s[r].t=i; 107 s[r+1].l=INF; 108 } 109 rr=1; 110 S[1].l=MAX; 111 S[2].l=INF; 112 S[1].t=n; 113 MIN=t[1].t; 114 for (i=2; i<n; i++) 115 if (t[i].t<MIN) vv2[i]=1; 116 else 117 MIN=t[i].t,vv2[i]=0; 118 for (i=n-1; i>=1; i--) 119 if (!vv2[i]) 120 { 121 while (rr && work(i,S[rr].l)<=work(S[rr].t,S[rr].l)) rr--; 122 if (!rr) 123 { 124 rr=1; 125 S[1].l=MAX; 126 S[1].t=i; 127 continue; 128 } 129 L=S[rr].l; 130 R=S[rr+1].l; 131 mid=(L+R)/2.0; 132 for (int I=1; I<=80; I++) 133 { 134 if (work(i,mid)<=work(S[rr].t,mid)) 135 { 136 R=mid; 137 mid=(L+R)/2.0; 138 } 139 else 140 { 141 L=mid; 142 mid=(L+R)/2.0; 143 } 144 } 145 S[++rr].l=mid; 146 S[rr].t=i; 147 S[rr+1].l=INF; 148 } 149 cnt=0; 150 for (i=1; i<=r; i++) 151 { 152 p[++cnt].x=s[i].l; 153 p[cnt].y=1; 154 p[cnt].z=s[i].t; 155 } 156 for (i=1; i<=rr; i++) 157 { 158 p[++cnt].x=S[i].l; 159 p[cnt].y=0; 160 p[cnt].z=S[i].t; 161 } 162 sort(p+1,p+cnt+1,CMP); 163 X=Y=0; 164 ans=INF; 165 for (i=1; i<=cnt; i++) 166 { 167 if (p[i].y==1) X=p[i].z; 168 else Y=p[i].z; 169 // printf("%.5f\n",(double)p[i].x); 170 if (X && Y) ans=min(ans,work(X,p[i].x)-work(Y,p[i].x)); 171 } 172 printf("%.2f\n",fabs((double)ans)); 173 return 0; 174 } 175 }