传送门
写在前面:感觉线性基太蛋疼了
思路:
原始方程
f[i]=min(f[j]+∑ik=j+1b[k]∗(i−k)+a[i])j∈[0,i)
用前缀和优化
f[i]=min(f[j]+i∗(sum1[i]−sum1[j])−(sum2[i]−sum[j])+a[i])
其中
sum1[x]=∑xi=1b[i]
,
sum2[x]=∑xi=1b[i]∗i
复杂度
O(n2)
设x>y且x转移i比y转移i优,则有
(f[x]+sum2[x]−f[y]−sum2[y])sum1[x]−sum1[y]<i
注意:数据范围不全,a,b也属于long long范围
代码:
#include<bits/stdc++.h>
#define LL long long
#define M 1000003
using namespace std;
LL in()
{
LL t=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-48,ch=getchar();
return t;
}
int n,head=1,tail=1,q[M];
LL a[M],b[M],f[M],sum1[M],sum2[M];
double Get(int x,int y)
{
return (double)(f[x]+sum2[x]-f[y]-sum2[y])/(double)(sum1[x]-sum1[y]);
}
main()
{
n=in();
for (int i=1;i<=n;i++) a[i]=in();
for (int i=1;i<=n;i++)
b[i]=in(),
sum1[i]=sum1[i-1]+b[i],
sum2[i]=sum2[i-1]+b[i]*i;
for (int i=1;i<=n;i++)
{
while (head<tail&&Get(q[head+1],q[head])<i) head++;
f[i]=f[q[head]]+(sum1[i]-sum1[q[head]])*i-(sum2[i]-sum2[q[head]])+a[i];
while (head<tail&&Get(i,q[tail])<Get(q[tail],q[tail-1])) tail--;
q[++tail]=i;
}
printf("%lld",f[n]);
}