P3406 海底高鐵,差分
阿新 • • 發佈:2022-03-05
目錄
題目描述
題目背景
題目描述
該鐵路經過 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;
}