解析
预算费用,和Luogu P2365 任务安排一样
得到了同样的式子
但是我们发现 (sumt_i) 可能小于零
也就是说我们需要的斜率可能不再具有单调性
所以我们要维护整个凸壳
那么怎么找到最佳的决策点呢?
其实就是 (slope(m,m-1) < sumt_i) 且 (slope(m,m+1) >= sumt_i) 中的 (m)
于是我们可以二分整个凸壳,找到这样的点
也就是判断等价于 (slope(m , m + 1) >= sumt_i)
满足这个不等式的决策可能成为最有决策,记录下来
然后我们要找凸壳中更靠前的,于是 (r=mid-1)
(Code)
#include<cstdio>
using namespace std;
typedef long long LL;
const int N = 3e5 + 5;
int n , q[N];
LL f[N] , T[N] , C[N] , s , t , c;
double slope(int u , int v)
{
if (C[u] == C[v]) return 1.0 / 0.0;
return 1.0 * ((f[u] - s * C[u]) - (f[v] - s * C[v])) / (1.0 * C[u] - C[v]);
}
int search(int l , int r , int m)
{
if (l == r) return q[l];
int mid , res = r;
while (l <= r)
{
mid = (l + r) >> 1;
if (slope(q[mid] , q[mid + 1]) >= m) res = mid , r = mid - 1;
else l = mid + 1;
}
return q[res];
}
int main()
{
scanf("%d%lld" , &n , &s);
for(register int i = 1; i <= n; i++)
scanf("%lld%lld" , &t , &c) , T[i] = T[i - 1] + t , C[i] = C[i - 1] + c;
int r;
q[r = 1] = 0;
for(register int i = 1; i <= n; i++)
{
int j = search(1 , r , T[i]);
f[i] = f[j] + T[i] * (C[i] - C[j]) + s * (C[n] - C[j]);
while (r > 1 && slope(i , q[r]) < slope(q[r] , q[r - 1])) --r;
q[++r] = i;
}
printf("%lld" , f[n]);
}