日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3406 海底高铁(前缀和+差分+坑点)

發布時間:2024/1/8 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 海底高铁(前缀和+差分+坑点)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。