bzoj3203【sdoi2013】保护出题人
题目描述
输入格式
第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离。接下来n行每行两个空格隔开的正整数,第i + 1行为Ai和 Xi,分别表示相比上一关在僵尸队列排头增加血量为Ai 点的僵尸,排头僵尸从距离房子Xi米处开始接近。
输出格式
一个数,n关植物攻击力的最小总和 ,保留到整数。
数据范围及提示
对于100%的数据, 1≤n≤10^5,1≤d≤10^12,1≤x≤ 10^12,1≤a≤10^12
-
题解:
- 需要先分析一个是否合法的判定规则:
- 由于一只僵尸被杀死后会立刻攻击后面的僵尸,所以只要对于每一个僵尸满足可以杀死即可;
- 考虑到第$n$关,最小可防御的攻击力$y_{n}$即:$max \{ \frac{sum_{i}}{x+(i-1)d} \}: \ 1 \le i \le n \ $;
- 所以求出每关最小的$y_{n}$加起来,考虑快速求每关的$y_{n}$;
- 和题目中的加入顺序搭配一下即:$\frac{ sum_{n} - sum_{i-1} }{ x + (n-i)d }$;
- 即:$\frac{sum_{n} - sum{i-1}}{ x + nd - id }: 1 \le i \le n $;
- 可以看成定点$P(sum_{n},x+nd)$和点群$S:(sum_{i-1},id)$的斜率最大值;
- 注意到$S_{n}$一定在$S_{i}:1 \le i \lt n$的右上方,同时$P$一定在当前$S$的右上方;
- 所以对$S$维护一个下凸包,凸包上的点和$P$的斜率满足单峰函数;
- 三分求值;
-
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #define ll long long 5 using namespace std; 6 const int N = 100010; 7 const double eps = 1e-8; 8 ll n,d,m; 9 double x,sum[N],ans; 10 char gc(){ 11 static char *p1,*p2,s[1000000]; 12 if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin); 13 return(p1==p2)?EOF:*p1++; 14 } 15 ll rd(){ 16 ll x = 0; char c = gc(); 17 while(c<'0'||c>'9') c = gc(); 18 while(c>='0'&&c<='9') x = x * 10 + c - '0',c = gc(); 19 return x; 20 } 21 struct point{ 22 double x,y; 23 point(){} 24 point(double x,double y):x(x),y(y){} 25 point operator -(const point &a){return point(x-a.x,y-a.y);} 26 }ch[N],P,p; 27 int dcmp(double x){return (fabs(x)<eps)?0:x<0?-1:1;} 28 double Cro(point a,point b){return a.x*b.y - b.x*a.y;} 29 double calc(point a){return a.y/a.x;} 30 int main() 31 { //freopen("bzoj3203.in","r",stdin); 32 //freopen("bzoj3203.out","w",stdout); 33 n = rd(); d = rd(); 34 for(int i = 1;i <= n;i++){ 35 sum[i] = rd() + sum[i-1]; x = rd(); 36 p = point(d*i,sum[i-1]); 37 while(m>1&&Cro(ch[m]-ch[m-1],p-ch[m])<=0) m--; 38 ch[++m] = p; 39 P = point(x+i*d,sum[i]); 40 int l = 1,r = m; 41 while(r-l>=3){ 42 int Len = (r-l)/3,mid1 = l + Len,mid2 = r - Len; 43 if(dcmp(calc(P-ch[mid1])-calc(P-ch[mid2]))<=0) l = mid1; else r = mid2; 44 } 45 double mx = 0; 46 for(int j = l;j <= r;j++) mx = max(calc(P-ch[j]),mx); 47 ans += mx; 48 } 49 printf("%.0lf\n",ans); 50 return 0; 51 }//by tkys_Austin;