bzoj 2216 [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

HINT


传送门
……并不会写。。后面看代码还真是神了。。
题目要求的东西转化一下,其实就是求一个最小的整数p,满足:
aj+abs(ij)ai<=p
于是令f(i)为对于i的答案,那么
f(i)=max{aj+abs(ij)}ai
考虑一下去掉绝对值,这只要先正着来一遍,再倒着来一遍就好了。
那么假如说是正着来的,也就是假设 j<i
对于决策 k<j<i ,j比k优,那么
aj+ij>ak+ik
考虑i后移,比如i->i+1,那么两者变化为:
aj+i+1jak+i+1k
变化量各自是
i+1jiji+1kik
由于 j>k 所以 xj<xk ,而 f(i)=i 是一个上凸函数,
所以说变化量里,j的变化量>k的变化量,
所以就是说!k完全没用啦!
随着i的后移,决策点一定是单调移动的……这就是“决策单调性”
涨姿势了。。。啥?泥问我为啥是单调移动的?……
如果j比k优了k就没用了。。如果k比j优那还有点戏。。
所以如果当前决策点为pos,pos及之前的点都没用了,
要么不移动,往后移动的话,pos肯定也没用了……很容易yy的辣!

于是这个显而易见(……划掉)的决策单调性就出来了,
那么对于i,i之前的所有点决策点肯定<=i决策点,
i之后所有点决策点肯定>=i决策点。。
于是就出来了个整体二分的样子。。或者说框架?
就是记录当前决策点区间,还有当前处理的区间,
最坏 T(n)=2T(n/2)+O(n)O(nlogn)
这个写法实在是太神了……我队列yy了半年都无果QAQ……

#include<bits/stdc++.h>
using namespace std;
const int 
    N=500005;
int n,a[N],f[N];
void solve(int L,int R,int l,int r,bool flag){
    if (l>r) return;
    int pos=0,mid=(l+r)>>1;
    if (!flag && mid==1) return;
    if (flag && mid==n) return;
    double MAX=0.0;
    if (!flag){
        int t=min(R,mid-1);
        for (int i=L;i<=t;i++)
            if ((double)sqrt(mid-i)+a[i]>MAX)
                MAX=(double)sqrt(mid-i)+a[i],pos=i;
    } else{
        int t=max(L,mid+1);
        for (int i=t;i<=R;i++)
            if ((double)sqrt(i-mid)+a[i]>MAX)
                MAX=(double)sqrt(i-mid)+a[i],pos=i;
    }
    f[mid]=max(f[mid],(int)ceil(MAX)-a[mid]);
    solve(L,pos,l,mid-1,flag);
    solve(pos,R,mid+1,r,flag);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    solve(1,n,1,n,0),solve(1,n,1,n,1);
    for (int i=1;i<=n;i++)  printf("%d\n",f[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ThinFatty/article/details/78483115
今日推荐