1. 程式人生 > 其它 >P3406 海底高鐵,差分

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;
} 

時間複雜度

參考文章