[CEOI2004] 锯木场选址

记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
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值