[POI2011]Lightning Conductor
Posted yexinqwq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POI2011]Lightning Conductor相关的知识,希望对你有一定的参考价值。
动态规划!
这题是决策单调性$dp$,我们把式子变形一下:
$$p_i=maxlimits^{n}_{j=1}{val_j+sqrt{|i-j|}}-a_i$$
看这绝对值很不爽,我们可以正着扫一遍,再把序列翻转扫一遍,就解决了绝对值问题了
我们只讨论前一部分,设:
$$f_j=val_j+sqrt{i-j}$$
那么我们要求的就是这个函数的最大值
显然,对于其中任意两个相邻的函数$f_t,f_{t+1}$,它们都有一个临界值$k_{t,t+1}$
显然序列中的$k_{1,2},k_{2,3}...$也要严格递增。否则,如果$k_{t,t+1}ge k_{t+1,t+2}$可以想象$f_{t+1}$?根本没有用。
那么我们可以用队列模拟二分栈,代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define N 500007 #define Get(i,j) val[j]+sq[i-j] using namespace std; int n; int val[N],que[N],k[N]; double sq[N],f[N]; int Search(int x,int y) { int l=y,r=k[x]?k[x]:n,mid,ans=r+1; while(l<=r) { mid=l+((r-l)>>1); if(Get(mid,x)<=Get(mid,y)) ans=mid,r=mid-1; else l=mid+1; } // cout<<"ans:"<<ans<<endl; return ans; } void Work() { memset(k,0,sizeof(k)); int head=1,tail=0; // memset(que,0,sizeof(que)); for(int i=1;i<=n;++i) { while(head<tail&&k[head]<=i) ++head; f[i]=max(f[i],(double)Get(i,que[head])); while(head<tail&&Get(k[tail-1],que[tail])<=Get(k[tail-1],i)) --tail; k[tail]=Search(que[tail],i); que[++tail]=i; // cout<<"f[i]:"<<f[i]<<endl; } } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&val[i]),sq[i]=sqrt(i); Work(); // printf(" "); // for(int i=1;i<=n;++i) // printf("%d ",k[i]); // printf(" "); reverse(val+1,val+1+n); reverse(f+1,f+1+n); Work(); // printf(" "); // for(int i=1;i<=n;++i) // printf("%d ",k[i]); // printf(" "); for(int i=n;i>=1;--i) printf("%d ",max((int)ceil(f[i])-val[i],0)); return 0; }
以上是关于[POI2011]Lightning Conductor的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2216[Poi2011]Lightning Conductor 决策单调性