BZOJ2216 [POI2011] Lightning Conductor

https://www.luogu.com.cn/problem/P3515

即计算最大的aj-ai+sqrt(|i-j|)。先考虑i>j的情况,此时可以验证有决策单调性:当决策点x,y和待计算点i,j满足x<y<i<j时,证明:若ax-ai+sqrt(|i-x|)<ay-ai+sqrt(|i-y|),则必有ax-aj+sqrt(|j-x|)<ay-aj+sqrt(|j-y|)。证明方法把前式的i移到一边然后分子有理化发现单调性即可。i<j时把a反过来同理。

决策单调性的一般方法是:队列维护决策点及其控制区间(这个控制区间是i~n的,是在仅考虑1~i-1的决策点时的情况,而不一定是最终的),然后用队头(此时它控制i)更新dp(i),并加入决策点i。加入时,从队尾弹出“用i更新某区间左端点,比用原控制该区间的点来更新该区间左端点更好”的区间(即把他们归为i的控制区间),然后在弹完后的队尾的那个区间找到“恰好归i控制的下标最小的点”,从而把该区间劈成两半。劈完后的后一半与原来弹出的那些区间之并即成为i的控制区间。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 
 5 int n;
 6 #define maxn 500011
 7 int head,tail,a[maxn];
 8 struct quenode{int p,l,r;}que[maxn];
 9 double f[maxn],g[maxn];
10 double cal(int j,int i) {return a[j]+sqrt(i-j)-a[i];}
11 void dp(double *f)
12 {
13     head=tail=1;
14     for (int i=1;i<=n;i++)
15     {
16         if (head<tail) f[i]=cal(que[head].p,i);
17         que[head].l++;
18         if (head<tail && que[head].l>que[head].r) head++;
19         while (head<tail && cal(que[tail-1].p,que[tail-1].l)<cal(i,que[tail-1].l)) tail--;
20         if (head==tail) que[tail++]=(quenode){i,i+1,n};
21         else
22         {
23             int L=que[tail-1].l,R=que[tail-1].r+1;
24             while (L<R)
25             {
26                 int mid=(L+R)>>1;
27                 if (cal(que[tail-1].p,mid)>cal(i,mid)) L=mid+1;
28                 else R=mid;
29             }
30             if (L<=n)
31             {
32                 que[tail-1].r=L-1;
33                 que[tail++]=(quenode){i,L,n};
34             }
35         }
36     }
37 }
38 
39 int main()
40 {
41     scanf("%d",&n);
42     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
43     dp(f);
44     for (int i=1;i+i<=n;i++) {int t=a[i]; a[i]=a[n-i+1]; a[n-i+1]=t;}
45     dp(g);
46     for (int i=1;i<=n;i++) printf("%.0lf\n",max(0.,ceil(max(f[i],g[n-i+1]))));
47     return 0;
48 }
View Code

 

posted @ 2020-01-31 11:50  Blue233333  阅读(125)  评论(0编辑  收藏  举报