bzoj4570 [Scoi2016]妖怪
2016-11-26 23:48
176 查看
【题意】平面中给出n个点,请你设定一个k值,使得过每个点作一条k<0的直线,每条直线横纵截距之和的最大值最小。
【数据范围】n<=10^6
【思路】二分答案,TLE
正解是求出一个上凸壳,对于凸壳上的每个点,计算出它是最大值时k的范围,更新答案。
【时间复杂度】O(n log n)#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000010
#define inf 2147483647
using namespace std;
struct aa{int w1, w2;}a
;
int n, w1
, w2
, l1, d
;
double ans, last, now, p;
inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
bool cmp(aa a, aa b){
if(a.w1!=b.w1)return a.w1<b.w1;
return a.w2<b.w2;
}
double slop(int i, int j){return 1.0*(a[i].w2-a[j].w2)/(a[i].w1-a[j].w1);}
int main(){
n=read();
for(int i=1; i<=n; i++){a[i].w1=read(); a[i].w2=read();}
sort(a+1, a+1+n, cmp); l1=0;
for(int i=1; i<=n; i++){
while(l1&&a[d[l1]].w2<=a[i].w2)l1--;
while(l1>=2&&slop(d[l1-1], d[l1])<=slop(d[l1], i))l1--;
d[++l1]=i;
}
for(int i=1; i<=l1; i++){w1[i]=a[d[i]].w1; w2[i]=a[d[i]].w2;}
ans=inf; last=0;
for(int i=1; i<=l1; i++){
if(i<=l1-1)now=-slop(d[i], d[i+1]); else now=inf;
p=sqrt(1.0*w2[i]/w1[i]);
if(last<=p&&p<=now)ans=min(ans, w1[i]+w2[i]+2*sqrt(w1[i])*sqrt(w2[i]));
else if(now<p)ans=min(ans, w1[i]+w2[i]+w1[i]*now+1.0*w2[i]/now);
else ans=min(ans, w1[i]+w2[i]+w1[i]*last+1.0*w2[i]/last);
last=now;
}
printf("%.4f", ans);
return 0;
}
【数据范围】n<=10^6
【思路】二分答案,TLE
正解是求出一个上凸壳,对于凸壳上的每个点,计算出它是最大值时k的范围,更新答案。
【时间复杂度】O(n log n)#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000010
#define inf 2147483647
using namespace std;
struct aa{int w1, w2;}a
;
int n, w1
, w2
, l1, d
;
double ans, last, now, p;
inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
bool cmp(aa a, aa b){
if(a.w1!=b.w1)return a.w1<b.w1;
return a.w2<b.w2;
}
double slop(int i, int j){return 1.0*(a[i].w2-a[j].w2)/(a[i].w1-a[j].w1);}
int main(){
n=read();
for(int i=1; i<=n; i++){a[i].w1=read(); a[i].w2=read();}
sort(a+1, a+1+n, cmp); l1=0;
for(int i=1; i<=n; i++){
while(l1&&a[d[l1]].w2<=a[i].w2)l1--;
while(l1>=2&&slop(d[l1-1], d[l1])<=slop(d[l1], i))l1--;
d[++l1]=i;
}
for(int i=1; i<=l1; i++){w1[i]=a[d[i]].w1; w2[i]=a[d[i]].w2;}
ans=inf; last=0;
for(int i=1; i<=l1; i++){
if(i<=l1-1)now=-slop(d[i], d[i+1]); else now=inf;
p=sqrt(1.0*w2[i]/w1[i]);
if(last<=p&&p<=now)ans=min(ans, w1[i]+w2[i]+2*sqrt(w1[i])*sqrt(w2[i]));
else if(now<p)ans=min(ans, w1[i]+w2[i]+w1[i]*now+1.0*w2[i]/now);
else ans=min(ans, w1[i]+w2[i]+w1[i]*last+1.0*w2[i]/last);
last=now;
}
printf("%.4f", ans);
return 0;
}
相关文章推荐
- bzoj 4570: [Scoi2016]妖怪 凸包
- [BZOJ]4570 [SCOI2016] 妖怪 凸包 + 双钩函数求最值
- BZOJ4570: [Scoi2016]妖怪
- 【bzoj4570】[Scoi2016]妖怪 凸包
- [bzoj4570][scoi2016]妖怪 二分区间
- Bzoj4570--Scoi2016妖怪
- [Bzoj4570][Scoi2016]妖怪(右上凸包)
- bzoj4570 [Scoi2016]妖怪(凸包+对勾函数最值)
- BZOJ 4570: [Scoi2016]妖怪
- [BZOJ4570]-[Scoi2016]妖怪-凸包
- BZOJ4570:[SCOI2016]妖怪——题解
- 【BZOJ 4570】【SCOI 2016】妖怪
- BZOJ4570 [Scoi2016]妖怪
- 4570: [Scoi2016]妖怪
- bzoj 4569: [Scoi2016]萌萌哒 (st表+并查集)
- 【BZOJ4569】[Scoi2016]萌萌哒 倍增+并查集
- BZOJ 4569 [Scoi2016]萌萌哒 | ST表 并查集
- BZOJ 4568 [Scoi2016]幸运数字 ——线性基 倍增
- BZOJ4570 SCOI2016 妖怪 凸包+双钩函数求最值
- BZOJ 4567: [Scoi2016]背单词