学过斜率优化的同学应该知道只是一道板子题,这里我们给出一个不同的解法:
我们定义表示考虑到了第个点的最小代价是多少,那么我们可以得出这个转移式子:
其中
看着像不太好优化的样子,但是实际上我们发现是凸的,换句话说的决策点具有单调性。
这样我们考虑如果我们已经知道了一个状态,我们考虑它能更新哪些状态,不难发现,由于决策点具有单调性,那么我们可以二分一下它所影响的区间,具体我们画图来解释一下:
一开始所有点的最优决策点:
显然的决策点是,我们考虑这个决策点能影响的范围:
接着我们考虑,由于决策点具有单调性,那么一定是这样的:
或者是:
于是我们可以考虑维护一个栈,每个元素是一个二元组,分别代表区间的左端点和它的决策点是什么,考虑加入一个数:
如果栈顶元素的左端点(原决策点)比现在的决策点更劣,那么我们将这个区间全部舍弃,否则我们就在这个区间二分出改变的点,修改两个元素即可。
考虑到每一个决策点只会入栈和出栈一次,但是由于二分的存在,总复杂度是的。
代码实现:
//Optimize
#pragma GCC optimize("Ofast")
//Head File
#include<bits/stdc++.h>
using namespace std;
#define il inline
//Variable
#define ll long long
#define ull unsigned long long
#define db double
#define lb long double
//Debug
#define B cerr<<"Break Point"<<endl;
#define P(x) cerr<<#x<<' '<<"="<<' '<<(x)<<endl;
#define p(x) cerr<<#x<<' '<<"="<<' '<<(x)<<' ';
#define ml(x) cerr<<"Size of array is "<<x*4/1024/1024<<" MB"<<endl;
//Vector
#define vc vector
#define pub push_back
#define pob pop_back
#define vbe(x) x.begin(),x.end()
//Memset
#define ms(x) memset(x,0,sizeof(x))
#define MS(x) memset(x,0x3f3f3f3f,sizeof(x))
//Pair
#define fi first
#define se second
//File
#define fin(x) freopen(x,"r",stdin)
#define fou(x) freopen(x,"w",stdout)
void fio()
{
#ifndef ONLINE_JUDGE
freopen("sample.in","r",stdin);
freopen("sample.out","w",stdout);
#endif
}
void pti()
{
double timeuse = clock()*1000.0/CLOCKS_PER_SEC;
cerr<<"Timeuse "<<timeuse<<"ms"<<endl;
}
void end()
{
pti();
exit(0);
}
//Inf
#define INF 0x3f3f3f3f
#define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
//IO
namespace io
{
const int SIZ=55;int que[SIZ],op,qr;char ch;
template<class I>
il void gi(I &w)
{
ch=getchar(),op=1,w=0;while(!isdigit(ch)){if(ch=='-') op=-1;ch=getchar();}
while(isdigit(ch)){w=w*10+ch-'0';ch=getchar();}w*=op;
}
template<class I>
il void print(I w)
{
qr=0;if(!w) putchar('0');if(w<0) putchar('-'),w=-w;while(w) que[++qr]=w%10+'0',w/=10;
while(qr) putchar(que[qr--]);
}
}
using io::gi;
using io::print;
const int N=5e4+5;
struct node
{
int pos,b,e;
};
int n,top,stk[N],anc[N];
ll L,c[N],f[N],pre[N];
ll calc(int fa,int x)
{
ll t=pre[x]-pre[fa]-L-1;
return f[fa]+t*t;
}
int find(int x)
{
int l=stk[top],r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(calc(x,mid)<calc(anc[top],mid)) r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
fio();
gi(n),gi(L);
for(int i=1;i<=n;++i) gi(c[i]);
for(int i=1;i<=n;++i) pre[i]=pre[i-1]+c[i];
for(int i=1;i<=n;++i) pre[i]+=i;
int cur=0;
stk[++top]=1,++cur;
for(int i=1;i<=n;++i)
{
while(i==stk[cur+1]) ++cur;
f[i]=calc(anc[cur],i);
while(calc(i,stk[top])<calc(anc[top],stk[top])) --top;
int t=find(i);
if(t<=n) stk[++top]=t,anc[top]=i;
}
print(f[n]);
end();
}
来源:CSDN
作者:_DAG_
链接:https://blog.csdn.net/CaptainDAG/article/details/103717377