题意翻译
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;
}