[决策单调性][整体二分] 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 }