hdu 3507 Print Article —— 斜率优化DP

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3507

设 f[i],则 f[i] = f[j] + (s[i]-s[j])*(s[i]-s[j]) + m

即 f[j] + s[j]*s[j] = 2*s[i]*s[j] + f[i] - s[i]*s[i] - m

于是维护下凸包即可;

写成 double 的 slp 总是不对,把分母乘到对面就对了...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define db double
using namespace std;
typedef long long ll;
int const xn=5e5+5;
int n,m,q[xn];
ll f[xn],s[xn];
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return f?ret:-ret;
}
ll y(int i){return (ll)s[i]*s[i]+f[i];}
ll up(int i,int j){return y(i)-y(j);}
ll dn(int i,int j){return s[i]-s[j];}
db slp(int a,int b){return 1.0*(y(a)-y(b))/(s[a]-s[b]);}
int main()
{
  while(~scanf("%d%d",&n,&m))
    {
      memset(f,0,sizeof f);
      for(int i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];
      int h=0,t=0;
      for(int i=1;i<=n;i++)
    {
      //while(h<t&&slp(q[h+1],q[h])<=2*s[i])h++;//<=  
      while(h<t&&up(q[h+1],q[h])<=2*s[i]*dn(q[h+1],q[h]))h++;//顺序
      f[i]=f[q[h]]+(ll)(s[i]-s[q[h]])*(s[i]-s[q[h]])+m;
      //while(h<t&&slp(q[t],q[t-1])>=slp(i,q[t-1]))t--;//>=
      while(h<t&&up(q[t],q[t-1])*dn(i,q[t-1])>=up(i,q[t-1])*dn(q[t],q[t-1]))t--;
      q[++t]=i;
    }
      printf("%lld
",f[n]);
    }
  return 0;
}