POJ_1180
不妨设T[i]表示T1+T2+…+Ti,F[i]表示F1+F2+…+Fi,如果根据题目中的计算公式来算的话,就会得到f[i]=min{f[j]+(out[j]+S+T[i]-T[j])*(F[i]-F[j])},其中out[j]表示执行完j所在的batch的时间,这时我们就会发现状态转移方程中有两个变量f[j]、out[j],这样是没办法进行一维dp的。
然而我们换一个角度写dp方程,先将F[i]改成Fi+F(i+1)+…+Fn,这时可以得到另一种形式的状态转移方程f[i]=min{f[j]+(S+T[i]-T[j])*F[j+1]},也就是说执行batch j的花费看成不只包括batch j内所有jobs的花费,同时还包括因执行batch j而延迟执行后续其他batch所带来的损失。
这样状态转移方程中就只有f[j]一个变量了,后续的工作可以用斜率优化+单调队列完成。
#include<stdio.h>
#include<string.h>
#define MAXD 10010
int T[MAXD], F[MAXD], q[MAXD], N, S;
long long int f[MAXD];
void init()
{
int i, j, k;
scanf("%d", &S);
T[0] = 0;
for(i = 1; i <= N; i ++)
{
scanf("%d%d", &T[i], &F[i]);
T[i] += T[i - 1];
}
F[N + 1] = 0;
for(i = N; i > 0; i --)
F[i] += F[i + 1];
}
long long int getf(int i)
{
return f[i] - (long long int)T[i] * F[i + 1] + S * F[i + 1];
}
void solve()
{
int i, j, k, front, rear, x, y, z;
front = rear = 0;
q[rear ++] = 0;
f[0] = 0;
for(i = 1; i <= N; i ++)
{
while(front < rear - 1)
{
x = q[front], y = q[front + 1];
if((long long int)T[i] * (F[x + 1] - F[y + 1]) < getf(y) - getf(x))
break;
++ front;
}
j = q[front];
f[i] = f[j] + (long long int)(T[i] - T[j] + S) * F[j + 1];
q[rear] = i;
for(j = rear - 1; j > front; j --)
{
x = q[j - 1], y = q[j], z = q[j + 1];
if((F[y + 1] - F[z + 1]) * (getf(y) - getf(x)) < (F[x + 1] - F[y + 1]) * (getf(z) - getf(y)))
break;
q[rear = j] = q[j + 1];
}
++ rear;
}
printf("%lld\n", f[N]);
}
int main()
{
while(scanf("%d", &N) == 1)
{
init();
solve();
}
return 0;
}