P3406 海底高铁(前缀和+差分+坑点)
P3406 海底高鐵https://www.luogu.com.cn/problem/P3406https://www.luogu.com.cn/problem/P3406
分析
本題是一個典型的前綴和和差分的例題,題目難度不大,把題目樣例畫一下就能有大致思路
1. 題目的一個考察點在每條路段都有2種方案,辦卡或者不辦卡,那么就要考慮最便宜的情況
什么時候最便宜?
?辦卡的總消費C1 = 卡費 + 優惠價 * 經過次數
?不辦卡的總費用C2 = 原價 * 經過次數
如果C1 < C2,那么就選擇辦卡,這里的的未知數只有一個——>經過次數
?2. 現在問題就來到了怎么求經過次數,如果你選擇一個個點的去模擬,那么這個題你就會TLE,所以這里我們采用差分的方法來實現
何為差分:
我們可以發現,每次一個區間內的數同時加上一個數,它們的差值是不會變的。這也是差分的思想。
用數組一個b,b[i]=a[i]-a[i-1],即b[i]表示第i項較前一項(第i-1項)的增量。 需要注意的是,b[1]=a[1]。 (同樣的,我們可以優化到不使用a數組,不過需要記錄前一項的值)
當[x,y]區間內的數都加上z時,a[x]+=z(第x項比其前一項的增量增加z), a[y+1]-=z(第y+1項比其前一項的增量減少z,因為第y項變大了!)。 這樣我們就很輕松地維護了區間內的變化。
顯然,由于b[i]都是第i項較前一項的增量,我們將b數組累加就可以求得指定項的數。即,a[i]=b[1]+b[2]+...+b[i](這里用前綴和來加)
?
這里你就可以發現:用差分來增加每段的經過次數,只要給頭和尾做操作,而不用差分的話就要給區間內的所有數+1,時間消耗就大大增加了
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];}//維護cnt[l,r),cnt[l,r)中每個值都+1,表示經過次數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; }坑點
自己給數據都開了long long卻依然通不過,后來發現了問題所在
我在最后求和的時候采用了如下比較的方法
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]對于返回給ans的(sum[a] - sum[b])并沒有用long long返回所以就出錯了
如果改成
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];}就對了 或者在前面加ll也能對
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函數應該也要這樣做
總結
以上是生活随笔為你收集整理的P3406 海底高铁(前缀和+差分+坑点)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 今日芯声 | 四大运营商之一居然不支持华
- 下一篇: 设置开机自启动项