解析
设 \(dp_i\) 表示处理完前 \(i\) 个时所花费的最小费用加上 \(i\) 因多分一组对后面产生的费用
\(dp_i = dp_j + sumt_i \times (sumf_i - sumf_j) + S \times (sumf_n - sumf_j)\)
然后斜率优化即可(\(n^2\) 其实可过)
对于两个状态 \(j,k\),当 \(dp_j - S \times sumf_j - (dp_k - S \times sumf_k) < sumt_i\) 时 \(j\) 更优
维护下凸壳,斜率和横坐标都单调增,单调队列简单维护即可
\(Code\)
#include<cstdio>
using namespace std;
typedef long long LL;
const int N = 5005;
int n , t[N] , f[N] , q[N];
LL S , st[N] , sf[N] , dp[N];
double slope(int x , int y)
{
return 1.0 * (dp[x] - S * sf[x] - dp[y] + S * sf[y]) / (1.0 * sf[x] - sf[y]);
}
int main()
{
scanf("%d%lld" , &n , &S);
for(register int i = 1; i <= n; i++)
scanf("%d%d" , &t[i] , &f[i]) , st[i] = st[i - 1] + t[i] , sf[i] = sf[i - 1] + f[i];
int h = 1 , t = 1;
for(register int i = 1; i <= n; i++)
{
while (h < t && slope(q[h] , q[h + 1]) < st[i]) h++;
dp[i] = dp[q[h]] + st[i] * (sf[i] - sf[q[h]]) + S * (sf[n] - sf[q[h]]);
while (t > h && slope(q[t] , q[t - 1]) > slope(q[t] , i)) t--;
q[++t] = i;
}
printf("%lld" , dp[n]);
}