P3406 海底高铁(前缀和+差分+坑点)
P3406 海底高鐵https://www.luogu.com.cn/problem/P3406https://www.luogu.com.cn/problem/P3406
分析
本題是一個(gè)典型的前綴和和差分的例題,題目難度不大,把題目樣例畫一下就能有大致思路
1. 題目的一個(gè)考察點(diǎn)在每條路段都有2種方案,辦卡或者不辦卡,那么就要考慮最便宜的情況
什么時(shí)候最便宜?
?辦卡的總消費(fèi)C1 = 卡費(fèi) + 優(yōu)惠價(jià) * 經(jīng)過次數(shù)
?不辦卡的總費(fèi)用C2 = 原價(jià) * 經(jīng)過次數(shù)
如果C1 < C2,那么就選擇辦卡,這里的的未知數(shù)只有一個(gè)——>經(jīng)過次數(shù)
?2. 現(xiàn)在問題就來到了怎么求經(jīng)過次數(shù),如果你選擇一個(gè)個(gè)點(diǎn)的去模擬,那么這個(gè)題你就會(huì)TLE,所以這里我們采用差分的方法來實(shí)現(xiàn)
何為差分:
我們可以發(fā)現(xiàn),每次一個(gè)區(qū)間內(nèi)的數(shù)同時(shí)加上一個(gè)數(shù),它們的差值是不會(huì)變的。這也是差分的思想。
用數(shù)組一個(gè)b,b[i]=a[i]-a[i-1],即b[i]表示第i項(xiàng)較前一項(xiàng)(第i-1項(xiàng))的增量。 需要注意的是,b[1]=a[1]。 (同樣的,我們可以優(yōu)化到不使用a數(shù)組,不過需要記錄前一項(xiàng)的值)
當(dāng)[x,y]區(qū)間內(nèi)的數(shù)都加上z時(shí),a[x]+=z(第x項(xiàng)比其前一項(xiàng)的增量增加z), a[y+1]-=z(第y+1項(xiàng)比其前一項(xiàng)的增量減少z,因?yàn)榈趛項(xiàng)變大了!)。 這樣我們就很輕松地維護(hù)了區(qū)間內(nèi)的變化。
顯然,由于b[i]都是第i項(xiàng)較前一項(xiàng)的增量,我們將b數(shù)組累加就可以求得指定項(xiàng)的數(shù)。即,a[i]=b[1]+b[2]+...+b[i](這里用前綴和來加)
?
這里你就可以發(fā)現(xiàn):用差分來增加每段的經(jīng)過次數(shù),只要給頭和尾做操作,而不用差分的話就要給區(qū)間內(nèi)的所有數(shù)+1,時(shí)間消耗就大大增加了
AC CODE
#include <iostream> using namespace std; const int maxn = 100000 + 5; typedef long long ll; struct rail {ll ori_pri, card, sal_pri; } rail[maxn];ll sum[maxn], co[maxn], ans; ll n, m, a[maxn], cnt[maxn], b[maxn];int main() {cin >> n >> m;for (int i = 0; i < m; i++)cin >> a[i];for (int i = 1; i < n; i++)cin >> rail[i].ori_pri >> rail[i].sal_pri >> rail[i].card;for (int i = 0; i < m - 1; i++){int l, r;if (a[i] > a[i + 1]){l = a[i + 1];r = a[i];}else{l = a[i];r = a[i + 1];}//維護(hù)cnt[l,r),cnt[l,r)中每個(gè)值都+1,表示經(jīng)過次數(shù)b[l] += 1;b[r] -= 1;}b[0] = cnt[0] = 0;for (int i = 1; i < n; i++)cnt[i] = b[i] + cnt[i - 1];for (int i = 1; i < n; i++){ll c1 = rail[i].card + rail[i].sal_pri * cnt[i];ll c2 = rail[i].ori_pri * cnt[i];if (c1 < c2){ans += rail[i].card;co[i] = rail[i].sal_pri;}elseco[i] = rail[i].ori_pri;}for (int i = 1; i < n; i++)sum[i] = sum[i - 1] + co[i];for (int i = 0; i < m - 1; i++){int next = a[i + 1];ans += a[i] > a[i + 1] ? (ll)sum[a[i] - 1] - (ll)sum[a[i + 1] - 1] : (ll)sum[a[i + 1] - 1] - (ll)sum[a[i] - 1];}cout << ans;return 0; }坑點(diǎn)
自己給數(shù)據(jù)都開了long long卻依然通不過,后來發(fā)現(xiàn)了問題所在
我在最后求和的時(shí)候采用了如下比較的方法
for (int i = 0; i < m - 1; i++){int next = a[i + 1];ans += a[i] > a[i + 1] ? sum[a[i] - 1] - sum[a[i + 1] - 1] : sum[a[i + 1] - 1] - sum[a[i] - 1];}不知道是不是在這種比較大小里
ans = a > b ? sum[a]-sum[b] : sum[b]-sum[a]對(duì)于返回給ans的(sum[a] - sum[b])并沒有用long long返回所以就出錯(cuò)了
如果改成
for (int i = 0; i < m - 1; i++){int next = a[i + 1];if (a[i] > a[i + 1])ans += sum[a[i] - 1] - sum[a[i + 1] - 1];elseans += sum[a[i + 1] - 1] - sum[a[i] - 1];}就對(duì)了 或者在前面加ll也能對(duì)
for (int i = 0; i < m - 1; i++){int next = a[i + 1];ans += a[i] > a[i + 1] ? (ll)sum[a[i] - 1] - (ll)sum[a[i + 1] - 1] : (ll)sum[a[i + 1] - 1] - (ll)sum[a[i] - 1];}同理 max和min函數(shù)應(yīng)該也要這樣做
總結(jié)
以上是生活随笔為你收集整理的P3406 海底高铁(前缀和+差分+坑点)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 今日芯声 | 四大运营商之一居然不支持华
- 下一篇: 设置开机自启动项