zl程序教程

您现在的位置是:首页 >  其它

当前栏目

城市交通

2023-09-27 14:28:26 时间

城市交通 ⁡ \operatorname{城市交通}

题目链接: jzoj 1749 ⁡ \operatorname{jzoj\ 1749} jzoj 1749

题目

编号为 1 ∼ n 1\sim n 1n n n n 个城市,每个城市有两个权值 A i A_i Ai B i B_i Bi

对于两个城市 i i i j j j i i i 可到 j j j 当且仅当 j > i j>i j>i ,而费用为 ( j − i ) ∗ A i + B j (j-i)*A_i+B_j (ji)Ai+Bj

求从城市 1 1 1 到城市 n n n 的最小费用。

输入

第一行一个正整数 n n n

第二行 n n n 个正整数,第 i i i 个表示 A i A_i Ai

第三行 n n n 个正整数,第 i i i 个表示 B i B_i Bi

输出

一个数,表示最小的费用。

样例输入

4
2 9 5 4
9 1 2 2

样例输出

8

数据范围

对于 20 % 20\% 20% 的数据, 1 < = n < = 100 1<=n<=100 1<=n<=100
对于 50 % 50\% 50% 的数据, 1 < = n < = 3000 1<=n<=3000 1<=n<=3000
对于 100 % 100\% 100% 的数据, 1 < = n < = 100000 , 1 < = A i , B i < = 1 0 9 1<=n<=100000,1<=A_i,B_i<=10^9 1<=n<=1000001<=Ai,Bi<=109

思路

这道题用dp来做。

f [ i ] f[i] f[i] 为从 1 1 1 走到 i i i 最少的体力。
那就从前面可以作为起点的所有点作为开始走的点,找到费用最小的一个。

最后输出 f [ n ] f[n] f[n] 就可以了。

代码

#include<cstdio>
#include<cstring>
#define ll long long
#define min(x, y) (x) < (y) ? (x) : (y)

using namespace std;

int n, use[100001], k;
ll a[100001], b[100001], f[100001];
bool yes;

int main() {
	scanf("%d", &n);//读入
	for (int i = 1; i <= n; i++)
		scanf("%lld", &a[i]);//读入
	for (int i = 1; i <= n; i++)
		scanf("%lld", &b[i]);//读入
	
	memset(f, 0x7f, sizeof(f));//初始化
	f[1] = 0;
	use[++k] = 1;
	for (int i = 2; i <= n; i++) {
		yes = 1;
		for (int j = 1; j <= k; j++) {
			f[i] = min(f[i], f[use[j]] + a[use[j]] * (i - use[j]) + b[i]);//从哪里走
			if (a[i] > a[use[j]] && b[i] > b[use[j]]) yes = 0;
		}
		if (yes) use[++k] = i;//可以作为起点
	}
	
	printf("%lld", f[n]);//输出
	
	return 0;
}