链接:点击打开链接
题意:给出n个数,要求按顺序全部取出,每次取出一段所花费的费用为取出一段数的和的平方加m,问最小费用是多少
代码1:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int a[500005],q[500005],dp[500005];
int in(int k1,int k2,int ai){
int x1,x2;
x1=dp[k2]-dp[k1]+a[k2]*a[k2]-a[k1]*a[k1];
x2=2*ai*(a[k2]-a[k1]);
if(x1<=x2)
return 1;
return 0;
}
int out(int k1,int k,int k2){
int x1,x2;
x1=(dp[k]-dp[k1]+a[k]*a[k]-a[k1]*a[k1])*(a[k2]-a[k]);
x2=(dp[k2]-dp[k]+a[k2]*a[k2]-a[k]*a[k])*(a[k]-a[k1]);
if(x1>=x2)
return 1;
return 0;
}
int main(){ //dp[i]表示输出到第i位的最小费用
int n,m,i,l,r,k,k1,k2,cas; //因此很容易推出dp[i]=min(dp[i],dp[j]+(sum[i]-sum[j])^2+m)
while(scanf("%d%d",&n,&m)!=EOF){ //但是复杂度为O(n^n),一定会超时,
for(i=1;i<=n;i++)
scanf("%d",&a[i]); //假设j<k,假设k优于j
for(i=2;i<=n;i++) //dp[k]+(sum[i]-sum[k])^2+m<dp[j]+(sum[i]-sum[j])^2+m
a[i]+=a[i-1]; //G[j,k]=((dp[k]+sum[k]^2)-(dp[j]+sum[j]^2))/(2*sum[j]*(sum[k]-sum[j]))<=1时
memset(dp,0,sizeof(dp)); //假设成立,也就是k优于j,否则j优于k
l=r=0; //当k1<k<k2时,G[k1,k]>=G[k,k2]时,k没有用处
q[0]=0;
for(i=1;i<=n;i++){
while(r-l>0){
k1=q[l],k2=q[l+1];
if(in(k1,k2,a[i]))
l++;
else
break;
}
dp[i]=dp[q[l]]+(a[i]-a[q[l]])*(a[i]-a[q[l]])+m;
while(r-l>0){
k1=q[r-1],k=q[r],k2=i;
if(out(k1,k,k2))
r--;
else
break;
}
q[++r]=i;
}
printf("%d\n",dp[n]);
}
return 0;
}
代码2:
#include <math.h>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
long long sum[500005],que[500005];
long long a[500005],q[500005],dp[500005];
long long getx(long long x){
return 2*sum[x];
}
long long gety(long long x){
return dp[x]+sum[x]*sum[x];
}
long long cross(long long x1,long long y1,long long x2,long long y2,long long x3,long long y3){
return (y3-y1)*(x2-x1)-(y2-y1)*(x3-x1);
}
int main(){
long long i,k,n,m,head,tail;
while(scanf("%I64d%I64d",&n,&m)!=EOF){
sum[0]=0;
for(i=1;i<=n;i++){
scanf("%I64d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
memset(dp,0,sizeof(dp));
head=tail=0;
q[tail++]=0;
for(i=1;i<=n;i++){
k=sum[i];
while((head+1<tail)&&((gety(q[head+1])-gety(q[head]))<=k*(getx(q[head+1])-getx(q[head]))))
head++;
dp[i]=gety(q[head])-k*getx(q[head]);
dp[i]+=sum[i]*sum[i]+m;
while((head+1<tail)&&cross(getx(q[tail-2]),gety(q[tail-2]),getx(q[tail-1]),gety(q[tail-1]),getx(i),gety(i))<=0ll)
tail--;
q[tail++]=i;
}
printf("%I64d\n",dp[n]);
}
return 0;
}
代码2主要是根据点击打开链接这个链接进行的学习,用图进行结合,很好理解