【bzoj2216】[Poi2011]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

Sol

首先我们可以推出来:

\(f[i]=max(a_j+\sqrt{i-j})-a_i(j<i)\)

\(f[i]=max(a_j+\sqrt{j-i})-a_i(j>i)\)

然后我们可以分两次dp。

但是暴力dp是\(O(n^2)\)的,会TLE,我们发现这题满足决策单调性的性质。具体地,如果k这个位置的决策是j,那么对于任意\(i<j\),i就不会再产生任何贡献,因为根号的增长会越来越慢,j的增长会比i还要快。而且每个点的贡献区域一定是一个区间,这样的话我们可以进行整体二分,我们每次找到一个区间mid的决策位置pos(直接暴力找),然后根据\([l,mid)\)的决策区域是\([L,pos]\)\((mid,r]\)的决策区域是\([pos,R]\)继续进行求解,注意大小写,小写是处理区间,大写是可决策区间。

代码实现非常容易:

Code

#include <bits/stdc++.h>
using namespace std;
int id[500005],a[500005],n;double f[500005],ans[500005];
double get(int x,int y){return a[x]+f[abs(y-x)];}
void solve(int l,int r,int L,int R)
{
    if(l>r) return;
    int mid=(l+r)>>1,pos;double mx=0;
    for(int i=L;i<=mid&&i<=R;i++) if(get(i,mid)>mx) mx=get(i,mid),pos=i;
    ans[id[mid]]=max(ans[id[mid]],mx);
    solve(l,mid-1,L,pos);solve(mid+1,r,pos,R);
}
void rev(int n){for(int i=1,j=n;i<j;i++,j--) swap(id[i],id[j]),swap(a[i],a[j]);}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),id[i]=i,f[i]=sqrt(i);
    solve(1,n,1,n);rev(n);solve(1,n,1,n);
    for(int i=1;i<=n;i++) printf("%d\n",(int)ceil(ans[i]-a[n-i+1]));
}

猜你喜欢

转载自www.cnblogs.com/CK6100LGEV2/p/9451577.html
今日推荐