bzoj 2216: Lightning Conductor 单调队列优化dp

题目大意

已知一个长度为\(n\)的序列\(a_1,a_2,...,a_n\)对于每个\(1\leq i\leq n\),找到最小的非负整数\(p\)满足:
对于任意的\(j\), \(a_j \leq a_i + p - \sqrt{\vert{i-j}\vert{}}\)

题解

我们化简不等式+分类讨论可以得到:

\[f_i = max{\sqrt{i-j} + a_j} - a_i, \text{$j < i$} \]

\[f_i = max{\sqrt{j-i} + a_j} - a_i, \text{$j > i$} \]

我们可以正反都dp一遍,这样就剩下了一个式子:
\(f_i = max{\sqrt{i-j} + a_j} - a_i\)
我们发现,max中的式子是具有单调性的,什么单调性呢...
我们知道对于每个位置\(i\)都会选取一个最优决策点\(j\),
我们称\(j\)\(i\)做出了贡献,那么我们知道:
对于任意的一个点\(i\)一定会对一段区间连续地做出贡献.
并且下标和区间所对应的位置都是单调的.
我们可以采用一种二分式的单调队列来处理这个问题

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 500010;
double f[maxn],g[maxn];
int a[maxn];
inline double calc(int j,int i){
	return a[j] + sqrt(double(i-j));
}
struct Node{
	int p,l,r;
	Node(){}
	Node(int a,int b,int c){p=a;l=b;r=c;}
}q[maxn];
int l,r,n;
inline void dp(double *f){
	l = 0;r = -1;
	f[1] = .0;
	q[++r] = Node(1,2,n);
	for(int i=2;i<=n;++i){
		++q[l].l;
		while(i > q[l].r) ++l;
		f[i] = calc(q[l].p,i) - a[i];
		if(calc(q[r].p,n) > calc(i,n)) continue;
		while(l <= r && calc(q[r].p,q[r].l) < calc(i,q[r].l)) --r;
		if(l <= r){
			int ls = q[r].l,rs = q[r].r;
			int x = -1;
			while(ls <= rs){
				int mid = (ls+rs) >> 1;			
				if(calc(i,mid) >= calc(q[r].p,mid)) x = mid,rs = mid-1;
				else ls = mid+1;
			}
			q[r].r = x - 1;
			q[++r] = Node(i,x,n);
		}else q[++r] = Node(i,i+1,n);
	}
}
int main(){
	read(n);
	for(int i=1;i<=n;++i) read(a[i]);
	dp(f);reverse(a+1,a+n+1);
	dp(g);reverse(g+1,g+n+1);
	for(int i=1;i<=n;++i){
		printf("%d\n",(int)ceil(max(0.0,max(f[i],g[i]))));
	}
	getchar();getchar();
	return 0;
}
posted @ 2017-02-19 21:39  Sky_miner  阅读(322)  评论(0编辑  收藏  举报