【bzoj3203】[Sdoi2013]保护出题人 凸包+三分法
2016-03-14 15:01
351 查看
非常好的题目
山东二轮前几年还是不错的嘛
题解:http://www.cnblogs.com/iwtwiioi/p/4007263.html
前i个僵尸的血量和为sum[i]
那么第i关的攻击力就是
max{(sum[i]-sum[j-1])/(x[i]+i*d-j*d)}(1<=j<=i)
考虑一下为什么?
对于第i只僵尸,可以把前面i-1只僵尸的血量合到第i只上,取最大值已经保证了前i-1只僵尸符合条件
然后就是这个问题怎么快速求解
这个问题可以看做两个点之间的斜率
即所有(j*d,sum[j-1])与(x[i]+i*d,sum[i])之间斜率的最大值
显然这些能取到的点应该在下凸壳上
下凸壳上的点到这个询问的点的斜率是个单峰函数,所以可以三分
于是维护一个下凸壳,然后每次询问在下凸壳上三分即可
注意整数三分,需要判断到r-l<3时,对这几个数单独求解取最大
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 100100
using namespace std;
struct yts
{
double x,y;
}s[maxn];
double sum,d;
double ans;
int n,top;
yts operator-(yts x,yts y)
{
yts ans;
ans.x=x.x-y.x;ans.y=x.y-y.y;
return ans;
}
double operator*(yts x,yts y)
{
return x.x*y.y-x.y*y.x;
}
void insert(yts x)
{
while (top>1 && (x-s[top])*(s[top]-s[top-1])>=0) top--;
s[++top]=x;
}
double cal(yts a,yts b)
{
return (b.y-a.y)/(b.x-a.x);
}
double max(double x,double y) {return x>y?x:y;}
double calc(yts x)
{
int l=1,r=top;
while (r-l>=3)
{
int mid=l+(r-l)/3,midmid=r-(r-l)/3;
if (cal(s[mid],x)>cal(s[midmid],x)) r=midmid; else l=mid;
}
double ans=0.0;
for (int i=l;i<=r;i++) ans=max(ans,cal(s[i],x));
return ans;
}
int main()
{
scanf("%d%lf",&n,&d);
top=0;sum=0;ans=0;
for (int i=1;i<=n;i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
yts t;
t.x=(double)i*d;t.y=sum;
insert(t);
sum+=x;
t.x=y+(double)i*d;t.y=sum;
ans+=calc(t);
}
printf("%.0lf\n",ans);
return 0;
}
山东二轮前几年还是不错的嘛
题解:http://www.cnblogs.com/iwtwiioi/p/4007263.html
前i个僵尸的血量和为sum[i]
那么第i关的攻击力就是
max{(sum[i]-sum[j-1])/(x[i]+i*d-j*d)}(1<=j<=i)
考虑一下为什么?
对于第i只僵尸,可以把前面i-1只僵尸的血量合到第i只上,取最大值已经保证了前i-1只僵尸符合条件
然后就是这个问题怎么快速求解
这个问题可以看做两个点之间的斜率
即所有(j*d,sum[j-1])与(x[i]+i*d,sum[i])之间斜率的最大值
显然这些能取到的点应该在下凸壳上
下凸壳上的点到这个询问的点的斜率是个单峰函数,所以可以三分
于是维护一个下凸壳,然后每次询问在下凸壳上三分即可
注意整数三分,需要判断到r-l<3时,对这几个数单独求解取最大
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 100100
using namespace std;
struct yts
{
double x,y;
}s[maxn];
double sum,d;
double ans;
int n,top;
yts operator-(yts x,yts y)
{
yts ans;
ans.x=x.x-y.x;ans.y=x.y-y.y;
return ans;
}
double operator*(yts x,yts y)
{
return x.x*y.y-x.y*y.x;
}
void insert(yts x)
{
while (top>1 && (x-s[top])*(s[top]-s[top-1])>=0) top--;
s[++top]=x;
}
double cal(yts a,yts b)
{
return (b.y-a.y)/(b.x-a.x);
}
double max(double x,double y) {return x>y?x:y;}
double calc(yts x)
{
int l=1,r=top;
while (r-l>=3)
{
int mid=l+(r-l)/3,midmid=r-(r-l)/3;
if (cal(s[mid],x)>cal(s[midmid],x)) r=midmid; else l=mid;
}
double ans=0.0;
for (int i=l;i<=r;i++) ans=max(ans,cal(s[i],x));
return ans;
}
int main()
{
scanf("%d%lf",&n,&d);
top=0;sum=0;ans=0;
for (int i=1;i<=n;i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
yts t;
t.x=(double)i*d;t.y=sum;
insert(t);
sum+=x;
t.x=y+(double)i*d;t.y=sum;
ans+=calc(t);
}
printf("%.0lf\n",ans);
return 0;
}
相关文章推荐
- UITextField加密输入属性
- css:position 与 z-index 问题(1)
- js判断当前环境是否为苹果手机
- viewpager+fragment
- weibo爬虫计划,以及普适爬虫框架的搭建
- NYOJ-背包问题
- Android之崩溃日志本地存储与远程保存
- java 中类加载过程
- java微信开发-token验证
- 基于redis的处理session的方法
- 从jQuery中学习来的另一种继承方式(技巧)
- for应用,转义字符,break和continue的区别
- NN学习笔记
- Linux基础回顾之基础命令四
- 视图控制器转场详解
- css3(border-radius) 边框圆角详解
- Android Material Design
- 快速幂
- uvaliva3403 Mobile Computing
- 谁来负责工具方法和静态方法的参数验证,调用者还是被调着?