[决策单调性][整体二分] Bzoj P2216 Lightning Conductor

Description


已知一个长度为n的序列a1,a2,...,an。
对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt(abs(i-j))

Input

第一行n,(1<=n<=500000)
下面每行一个整数,其中第i行是ai。(0<=ai<=1000000000)

 

Output

n行,第i行表示对于i,得到的p

 

Sample Input

6
5
3
2
4
2
4

Sample Output

2
3
5
3
5
4

 

题解

  • 随手化简就可以得到p>=aj-ai+sqrt(|i-j|) 
  • 我们发现其实只要求max(aj+sqrt(|i-j|))就好了
  • 不难发现这是有决策单调性的,那么就可以用整体二分来实现
  • 具体方法是二分一个中点mid,然后暴力求出mid的值,再把序列分成两半即可

 

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm> 
 6 #include <cstdlib>
 7 using namespace std;
 8 const int N=500010;
 9 int n,a[N],id[N];
10 double ans[N],f[N];
11 double get(int x,int y) { return a[x]+f[abs(x-y)]; }
12 void cdq(int l,int r,int L,int R)
13 {
14     if (l>r) return;
15     int mid=l+r>>1,pos=0; double mx=0;
16     for (int i=L;i<=R&&i<=mid;i++) if (get(i,mid)>mx) mx=get(i,mid),pos=i;
17     ans[id[mid]]=max(ans[id[mid]],mx),cdq(l,mid-1,L,pos),cdq(mid+1,r,pos,R);
18 } 
19 int main()
20 {
21     scanf("%d",&n);
22     for (int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=sqrt(i),id[i]=i;
23     cdq(1,n,1,n);
24     for (int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]),swap(id[i],id[n-i+1]);
25     cdq(1,n,1,n);
26     for (int i=1;i<=n;i++) printf("%d\n",(int)ceil(ans[i]-a[n-i+1]));
27 } 

 

posted @ 2019-07-07 12:03 BEYang_Z 阅读(...) 评论(...) 编辑 收藏