P3406 海底高铁,差分

题目传送门

题目描述

题目背景

题目描述

该铁路经过 NN 个城市,每个城市都有一个站。不过,由于各个城市之间不能协调好,于是乘车每经过两个相邻的城市之间(方向不限),必须单独购买这一小段的车票。第 ii 段铁路连接了城市 ii 和城市 i+1(1\leq i<N)i+1(1≤i<N)。如果搭乘的比较远,需要购买多张车票。第 ii 段铁路购买纸质单程票需要 A_iA**i 博艾元。

虽然一些事情没有协调好,各段铁路公司也为了方便乘客,推出了 IC 卡。对于第 ii 段铁路,需要花 C_iC**i 博艾元的工本费购买一张 IC 卡,然后乘坐这段铁路一次就只要扣 B_i(B_i<A_i)B**i(B**i<A**i) 元。IC 卡可以提前购买,有钱就可以从网上买得到,而不需要亲自去对应的城市购买。工本费不能退,也不能购买车票。每张卡都可以充值任意数额。对于第 ii 段铁路的 IC 卡,无法乘坐别的铁路的车。

Uim 现在需要出差,要去 MM 个城市,从城市 P_1P1 出发分别按照 P_1,P_2,P_3,\cdots,P_MP1,P2,P3,⋯,P**M 的顺序访问各个城市,可能会多次访问一个城市,且相邻访问的城市位置不一定相邻,而且不会是同一个城市。

现在他希望知道,出差结束后,至少会花掉多少的钱,包括购买纸质车票、买卡和充值的总费用。

输入格式

第一行两个整数,N,MN,M

接下来一行,MM 个数字,表示 P_iP**i

接下来 N-1N−1 行,表示第 ii 段铁路的 A_i,B_i,C_iA**i,B**i,C**i

输出格式

一个整数,表示最少花费

输入输出样例

输入 #1复制

9 10
3 1 4 1 5 9 2 6 5 3
200 100 50
300 299 100
500 200 500
345 234 123
100 50 100
600 100 1
450 400 80
2 1 10

输出 #1复制

6394

说明/提示

22 到 33 以及 88 到 99 买票,其余买卡。

对于 30%30% 数据 M=2M=2。

对于另外 30%30% 数据 N\leq1000,M\leq1000N≤1000,M≤1000。

对于 100%100% 的数据 M,N\leq 105,A_i,B_i,C_i\le105M,N≤105,A**i,B**i,C**i≤105。

算法求解

分析

用差分来统计每一段\(i -> i+1( 1\le i \le n-1)\)经过的次数,统计完了之后比较是买卡便宜还是买票便宜

注意

  • 根据行程进行差分加和的时候,先判断一下两个站点序号的大小
  • 最后的结果res用long long 类型,并且res计算过程中也需要用long long强制转化

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL; 
const int N = 100010;
int A[N], B[N], C[N];
int b[N]; // 表示差分
int path[N]; // 表示经过的路径
int n, m; 
void add(int l, int r)
{
	b[l] += 1;
	b[r+1] -= 1;
} 

int main()
{
	scanf("%d%d",&n, &m);
	for(int i = 0; i < m; i++) scanf("%d", &path[i]);
	// 初始是0,不用构造差分
	
	for(int i = 1; i <= n-1; i++)
	{
		scanf("%d%d%d", &A[i], &B[i], &C[i]); // i -> i+1
	}
	
	// 对每一段 path[i] -> path[i+1] 
	for(int i = 0; i < m-1; i++)
	{
		int x = path[i], y = path[i+1];
		if(x > y) swap(x, y);
		
		add(x, y-1);
	}
	
	// 求前缀和, b[i]表示每段站经过的次数 
	for(int i = 1; i <= n-1; i++) b[i] += b[i-1];
		
	LL res = 0;
	for(int i = 1; i <= n-1; i++)
	{
		LL fee1 = (LL)A[i] * b[i];
		LL fee2 = (LL)B[i] * b[i] + C[i];
		
		if(fee1 > fee2) res += fee2;
		else			res += fee1;	
	}	 
	cout << res << endl;
	return 0;
} 

时间复杂度

参考文章

posted @ 2022-03-05 11:36  VanHope  阅读(59)  评论(0编辑  收藏  举报