标签:print tor mat ace efi limit def UNC set
动态规划!
这题是决策单调性$dp$,我们把式子变形一下:
$$p_i=\max\limits^{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("\n");
// for(int i=1;i<=n;++i)
// printf("%d ",k[i]);
// printf("\n");
reverse(val+1,val+1+n);
reverse(f+1,f+1+n);
Work();
// printf("\n");
// for(int i=1;i<=n;++i)
// printf("%d ",k[i]);
// printf("\n");
for(int i=n;i>=1;--i)
printf("%d\n",max((int)ceil(f[i])-val[i],0));
return 0;
}
标签:print tor mat ace efi limit def UNC set
原文地址:https://www.cnblogs.com/yexinqwq/p/10223621.html