思路:这类问题有一个特点,n特别大 1e4以上,而且转移方程必须O(n^2)才能跑完。
通过化简式子可以找到优化的途径。
例如HYSBZ-1010
我们可以写出转移方程
假设k<j<i,且 j比k更优, 这时候会得到表达式
设,这时候会化简成
也就是最终转化成左边只有sum[i]的式子,这就相当于j,k两点的斜率,我们用单调队列维护一个斜率递增的j, k
对于top++, rear--操作:
当队列头的两个元素斜率小于sum【i】, 说明还能优化,所以top++,取更大的斜率
对于rear--是要维护一个下凸包。
#include<cstdio>
#include<iostream>
#include<cstring>
#define MAXN 500000+10
#define LARGE 23333333
using namespace std;
typedef long long LL;
int n, top, rear;
LL dp[MAXN], M, sum[MAXN], S[MAXN];
LL GetUp(int a, int b, int i)
{
return (dp[a]-2*(i-1-M)*a+a*a-2*(i-1-M)*sum[a]+2*a*sum[a]+sum[a]*sum[a])-
(dp[b]-2*(i-1-M)*b+b*b-2*(i-1-M)*sum[b]+2*b*sum[b]+sum[b]*sum[b]);
}
LL GetDown(int a, int b)
{
return 2*(a+sum[a]-b-sum[b]);
}
int main()
{
scanf("%d%lld", &n, &M);
LL tmp;
sum[0]=dp[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%lld", &tmp);
sum[i]=sum[i-1]+tmp;
}
top=rear=0;
S[rear++]=0;
for(int i=1; i<=n; i++)
{
while(top+1<rear && GetUp(S[top+1], S[top], i)<=GetDown(S[top+1], S[top])*sum[i]) top++;
int j=S[top];
dp[i]=dp[j]+(i-j-1+sum[i]-sum[j]-M)*(i-j-1+sum[i]-sum[j]-M);
while(top+1<rear &&
GetUp(i, S[rear-1], i)*GetDown(S[rear-1], S[rear-2])<=GetUp(S[rear-1], S[rear-2], i)*GetDown(i, S[rear-1]))rear--;
S[rear++]=i;
}
printf("%lld\n", dp[n]);
return 0;
}
#include<cstdio>
#include<iostream>
#include<cstring>
#define MAXN 500000+10
#define LL long long
#define LARGE 23333333
using namespace std;
int n, top, rear;
LL dp[MAXN], M, sum[MAXN], S[MAXN];
LL GetUp(int a, int b){
return (dp[a]+sum[a]*sum[a])-(dp[b]+sum[b]*sum[b]);
}
LL GetDown(int a, int b){
return 2*(sum[a]-sum[b]);
}
int main()
{
while(~scanf("%d%lld", &n, &M)){
LL tmp;
sum[0]=dp[0]=0;
for(int i=1; i<=n; i++){
scanf("%lld", &tmp);
sum[i]=sum[i-1]+tmp;
}
top=rear=0;
S[rear++]=0;
for(int i=1; i<=n; i++){
while(top+1<rear && GetUp(S[top+1], S[top])<=GetDown(S[top+1], S[top])*sum[i]) top++;
int j=S[top];
dp[i]=dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+M;
while(top+1<rear &&
GetUp(i, S[rear-1])*GetDown(S[rear-1], S[rear-2])<=GetUp(S[rear-1], S[rear-2])*GetDown(i, S[rear-1]))rear--;
S[rear++]=i;
}
printf("%lld\n", dp[n]);
}
return 0;
}