BZOJ2216: [Poi2011]Lightning Conductor

n个数,对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt(abs(i-j))。

这就是要找max(Aj-Ai+sqrt(abs(i-j))向上取整。把他分成两部分,Max(Max (Aj+sqrt(i-j)) , Max (Ak+sqrt(k-i))) j<=i<=k。

这个东西是有决策单调性的,假设一个Ax是从Aj那里转移过来的,先考虑j<x,那么j是比任意一个k,k<x,都要好,也就是

$A_j-A_x+sqrt(x-j) geq A_k-A_x+sqrt(x-k)$

整理下就是

$A_j-A_k geq sqrt(x-k)-sqrt(x-j) $

右边那个东西会随x的增大而减小,至于为什么,详见高中数学选修2-2函数求导。

反过来同理。这样的话,每次决策完一个点可以把序列分成两个部分分别再决策,这样可以抽象成一个若干层的树,每一层的复杂度都是n。为了使复杂度最小,采用整体二分。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 //#include<queue>
 6 #include<cmath>
 7 //#include<iostream>
 8 using namespace std;
 9 
10 int n;
11 #define maxn 500011
12 int a[maxn],f[maxn],g[maxn];
13 void solve1(int l,int r,int L,int R)
14 {
15     if (l>r) return;
16     int mid=(l+r)>>1,pos=0;
17     double Max=0;
18     for (int i=L;i<=R && i<=mid;i++)
19         if (1.0*a[i]+sqrt(mid-i)>Max) pos=i,Max=1.0*a[i]+sqrt(mid-i);
20     f[mid]=ceil(Max)-a[mid];
21     solve1(l,mid-1,L,pos);
22     solve1(mid+1,r,pos,R);
23 }
24 void solve2(int l,int r,int L,int R)
25 {
26     if (l>r) return;
27     int mid=(l+r)>>1,pos=0;
28     double Max=0;
29     for (int i=R;i>=L && i>=mid;i--)
30         if (1.0*a[i]+sqrt(i-mid)>Max) pos=i,Max=1.0*a[i]+sqrt(i-mid);
31     g[mid]=ceil(Max)-a[mid];
32     solve2(l,mid-1,L,pos);
33     solve2(mid+1,r,pos,R);
34 }
35 int main()
36 {
37     scanf("%d",&n);
38     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
39     solve1(1,n,1,n);
40     solve2(1,n,1,n);
41     for (int i=1;i<=n;i++) printf("%d
",max(f[i],g[i]));
42     return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/Blue233333/p/7651524.html