题意
给定一个序列,可以将其分为任意段,每一段的值为((len+L+sum C_i)),其中(L,C)给定。
求最大值。
思路
状态转移方程为(f[i]=min(f[j]+(i-j+sum[i]-sum[j]-L-1)^2))
涉及到了平方直接展开比较恶臭,考虑将常数与变量分离,可以得到(f[i]=f[j]+(sum[i]+i-L-1-sum[j]-j)^2)
现在再展开就解决了。
(end)。
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T>inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T>inline void write (T x) {
if (x<0) putchar('-'),x*=-1;
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Project {
#define int long long
const int N=50005;
int n,l,head,tail;
int sum[N],dp[N],queue[N];
inline double slope (int x,int y) {
return (double)(dp[x]+(sum[x]+x+l+1)*(sum[x]+x+l+1)-dp[y]-(sum[y]+y+l+1)*(sum[y]+y+l+1))/(double)(sum[x]+x-sum[y]-y);
}
inline void MAIN () {
read(n),read(l);
for (register int i=1; i<=n; ++i) {
read(sum[i]),sum[i]+=sum[i-1];
}
head=tail=1,queue[head]=0;
for (register int i=1; i<=n; ++i) {
while (head<tail&&slope(queue[head],queue[head+1])<=2*(sum[i]+i)) ++head;
dp[i]=dp[queue[head]]+(sum[i]+i-sum[queue[head]]-queue[head]-l-1)*(sum[i]+i-sum[queue[head]]-queue[head]-l-1);
while (head<tail&&slope(queue[tail-1],queue[tail])>=slope(queue[tail],i)) --tail;
queue[++tail]=i;
}
write(dp[n]);
}
#undef int
}
int main () {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
Project::MAIN();
}