【SPOJ】Lightning Conductor (dp+决策单调性)
题意翻译
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
由 @枫林晚 提供翻译
SOLUTION:
这题卡常啊qaq ,960ms卡过。。卡了好久。。。
关于dp方程的写法,看看其他的博客就行,主要是像联系决策单调性的写法
当踢出队尾时:
CODE:
#include<bits/stdc++.h> #define RG register #define R RG int #define G if(++ip==iend)fread(ip=buf,1,N,stdin) #define calc(i,j) a[j]+sq[i-j]//计算函数值 using namespace std; #define double long double const int N=5e5+9; char buf[N],*iend=buf+N,*ip=iend-1; int n,a[N],q[N],k[N]; double p[N],sq[N]; inline int read() { int X=0; bool flag=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();} while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();} if(flag) return X; return ~(X-1); } inline int in(){ int x;x=read();return x; } inline void chkmx(RG double&x,RG double y){ if(x<y)x=y; } inline int bound(int p,R x,R y){//二分临界值k R l=y+1,r=(n),m,ret=r+1;//控制二分上下界 while(l<=r){ m=(l+r)>>1; if(calc(m,x)<=calc(m,y)) ret=m,r=m-1; else l=m+1; } return ret; } void work(){ for(R h=1,t=0,i=1;i<=n;++i){ while(h<t&&k[h]<=i)++h;//将已经不优的决策出队 chkmx(p[i],calc(i,q[h]));//因为做两遍所以取max3 /// while(h<t&&bound(t,q[t-1],q[t])>=bound(t,q[t],i))--t;//这么写就T了 while(h<t&&k[t-1]>=bound(t,q[t],i))--t;//维护k单调 k[t]=bound(t,q[t],i); q[++t]=i; } } int main(){ // freopen("in.txt","r",stdin); n=in(); R i,j; // cout<<n<<endl; for(i=1;i<=n;++i) a[i]=in(),sq[i]=sqrt(i); // puts("###"); work(); for(i=1,j=n;i<j;++i,--j)//序列翻转 swap(a[i],a[j]),swap(p[i],p[j]); work(); for(R i=n;i;--i)//翻转过了所以要倒着输出 printf("%d\n",max((int)ceil(p[i])-a[i],0)); return 0; }