【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
",max((int)ceil(p[i])-a[i],0));
    return 0;
    
    
}

  

原文地址:https://www.cnblogs.com/zhangbuang/p/11253981.html