这类问题做的过程比较偏数学
对于状态转移方程需要经过一些数学上的整理
之后几道题步步深入斜率优化问题
https://www.acwing.com/problem/content/302/
#include
#include
using namespace std;
#include
const int N=5010;
int n,s;
int sumt[N],sumc[N];
int f[N];
int q[N];
int main(){
scanf("%d%d", &n, &s);
for(int i=1; i<=n; i++){
int t, c;
scanf("%d%d", &t, &c);
sumt[i] = sumt[i-1]+t;
sumc[i] = sumc[i-1]+c;
}
memset(f, 0x3f, sizeof f);
f[0] = 0;
for(int i=1; i<=n; i++)
for(int j=0; j<i; j++)
f[i] = min(f[i], f[j]+sumt[i]*(sumc[i]-sumc[j])+s*(sumc[n]-sumc[j]));
printf("%d\n", f[n]);
return 0;
}
https://www.acwing.com/problem/content/303/
这题仅仅是数据范围扩大了
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=300010;
int n,s;
ll c[N], t[N];
ll f[N];
int q[N];
int main(){
scanf("%d%d", &n, &s);
for(int i=1; i<=n; i++){
scanf("%lld%lld", &t[i], &c[i]);
t[i]+=t[i-1];
c[i]+=c[i-1];
}
int hh=0, tt=0;
q[0]=0;//f[0]也是一个可选答案
for(int i=1; i<=n; i++){
//队列中至少有两个数
while(hh < tt && (f[q[hh+1]]-f[q[hh]]) <= (t[i]+s)*(c[q[hh+1]]-c[q[hh]])) hh++;
int j = q[hh]; //对头,即第一个斜率大于当前斜率的点
f[i] = f[j]-(t[i]+s)*c[j]+t[i]*c[i]+s*c[n];
while(hh < tt && (f[q[tt]]-f[q[tt-1]])*(c[i]-c[q[tt]]) >= (f[i]-f[q[tt]])*(c[q[tt]]-c[q[tt-1]]))
tt--;//去掉队尾的
q[++tt] = i;
}
printf("%lld", f[n]);
return 0;
}
https://www.acwing.com/problem/content/304/
#include
#include
using namespace std;
const int N=300010;
typedef long long ll;
int n,s;
ll t[N],c[N];
ll f[N];
int q[N];
int main(){
scanf("%d%d", &n, &s);
for(int i=1; i<=n; i++){
scanf("%lld%lld", &t[i], &c[i]);
t[i]+=t[i-1];
c[i]+=c[i-1];
}
int hh=0, tt=0;
q[0]=0;
for(int i=1;i<=n;i++){
int l=hh, r=tt;
while(l<r){
int mid=l+r>>1;
if(f[q[mid+1]]-f[q[mid]]>(t[i]+s)*(c[q[mid+1]]-c[q[mid]]))r = mid;
else l=mid+1;
}
int j = q[r];
f[i] = f[j]-(t[i]+s)*c[j]+t[i]*c[i]+s*c[n];
while(hh < tt && (double)(f[q[tt]]-f[q[tt-1]])*(c[i]-c[q[tt-1]]) >= (double)(f[i]-f[q[tt-1]])*(c[q[tt]]-c[q[tt-1]]))
tt--;//去掉队尾的
q[++tt] = i;
}
printf("%lld", f[n]);
return 0;
}
https://www.acwing.com/problem/content/305/
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=100010, M=100010, P=110;
int n,m,p;
ll d[N], t[N], a[N], s[N];
ll f[P][M];
int q[M];
ll get_y(int k, int j){
return f[j-1][k]+s[k];
}
int main(){
scanf("%d%d%d", &n,&m,&p);
for(int i=2; i<=n; i++){
scanf("%lld", &d[i]);
d[i]+=d[i-1];
}
for(int i=1; i<=m; i++){
int h;
scanf("%d%lld", &h, &t[i]);
a[i] = t[i]-d[h];//直接过滤掉了其他的山,只剩下留小猫的
}
sort(a+1, a+m+1);
for(int i=1; i<=m; i++)s[i]=s[i-1]+a[i];
memset(f, 0x3f, sizeof f);
for(int j=0; j<=p; j++) f[j][0] = 0;//j个饲养员处理0只小猫都是0
for(int j=1; j<=p; j++){
int hh=0, tt=0;
q[0] = 0;
for(int i=1;i<=m;i++){
while(hh<tt && (get_y(q[hh+1],j)-get_y(q[hh],j))<=a[i]*(q[hh+1]-q[hh]))hh++;
int k = q[hh];
f[j][i] = f[j-1][k]-a[i]*k+s[k]+a[i]*i-s[i];
while(hh<tt && (get_y(q[tt],j)-get_y(q[tt-1],j))*(i-q[tt])>=
(get_y(i,j)-get_y(q[tt],j))*(q[tt]-q[tt-1]))tt--;
q[++tt]=i;
}
}
printf("%lld", f[p][m]);
return 0;
}