记Sw[i]为1-i的重量和 Sd[i]为1-i的路程和 w[i]为第i棵树重量
设j为i的最优决策点则有
F[i] = w[1]*(Sd[j] - Sd[1]) + w[2] * (Sd[j] - Sd[2]) + ....
+ w[j+1] * (Sd[i] - Sd[j+1]) + w[j+2] * (Sd[i] - Sd[j+2) + ...
+ w[i+1] * (Sd[n+1] - Sd[i+1]) + ... + w[n] * (Sd[n+1] - Sd[n])
提出式子中所有 -w[i] * Sd[i] 记为All
则有 F[i] = - All
+ w[1] * Sd[j] + w[2] * Sd[j] + ...
+ w[j+1] * Sd[i] + w[j+2] * Sd[i] + ..
+ w[i+1] * Sd[n+1] + ... + w[n] * Sd[n+1]
推得 F[i] = -All + (Sw[j-1] * Sd[j]) + ((Sw[i] - Sw[j]) * Sd[i]) + ((Sw[n+1] - Sw[i]) * Sd[n+1])
至于单调队列的性质和处理就交给论文说吧 这里不再说明
#include<cstdio>
#include<algorithm>
const int MAXN = 20000;
using namespace std;
typedef long long LL;
int Sw[MAXN+10], Sd[MAXN+10], Q[MAXN+10], d[MAXN+10], dis[MAXN+10];
int n, K, F, R, Ans;
void GET(int &x)
{
int s = 0, f = 1;
char c;
while(c = getchar(), c != ' ' && c != '\n')
if(c == '-') f = -1;
else
s = s * 10 + c - '0';
x = s * f;
}
double Slope(int i, int j)
{
return 1.0 * (Sw[i] * Sd[i] - Sw[j] * Sd[j]) / (Sw[i] - Sw[j]);
}
int main()
{
int All = 0;
GET(n);
for(int i = 1; i <= n; i++) GET(Sw[i]), GET(dis[i]);
for(int i = 1; i <= n+1; i++) {
Sd[i+1] = Sd[i] + dis[i];
All += Sd[i] * Sw[i];
Sw[i] += Sw[i-1];
}
int F, R;
F = R = 0;
Ans = (1 << 30) - 1;
for(int i = 1; i <= n; i++)
{
while(F < R - 1 && Slope(Q[R-1], Q[R-2]) >= Slope(i, Q[R-1]))
R--;
Q[R++] = i;
while(F < R - 1 && Slope(Q[F], Q[F+1]) <= Sd[i])
F++;
int tmp = -All + (Sw[i] - Sw[Q[F]]) * Sd[i] + (Sw[n] - Sw[i]) * Sd[n+1]+ Sw[Q[F]] * Sd[Q[F]];
Ans = min(Ans, tmp);
}
printf("%d", Ans);
}
/*
9
1 2
2 1
3 3
1 1
3 2
1 6
2 1
1 2
1 1
*/