CSP认证201809-4再卖菜[C++题解]:差分约束、前缀和
文章目錄
- 題目解答
- 題目鏈接
題目解答
來源:acwing
分析:
對于a0,a1,...,ana_0, a_1,...,a_na0?,a1?,...,an?,經過計算相鄰的數的平均值得到b0,b1,...,bnb_0, b_1,...,b_nb0?,b1?,...,bn?,現在給定序列b的值,反求序列a的值。
為了處理3者求和,我們使用前綴和的技巧求三個數或者2個數的和: ai?1+ai+ai+1=s[i+1]?s[i?2]a_{i-1}+a_i+a_{i+1} = s[i+1] - s[i-2]ai?1?+ai?+ai+1?=s[i+1]?s[i?2]
其實,bi=?ai?1+ai+ai+13?=?s[i+1]?s[i?2]3?b_i = \lfloor \frac{a_{i-1}+a_i+a_{i+1}}{3}\rfloor= \lfloor \frac{s[i+1] - s[i-2]}{3}\rfloorbi?=?3ai?1?+ai?+ai+1???=?3s[i+1]?s[i?2]??
等價于 3bi≤s[i+1]?s[i?2]≤3bi+2(1)3b_i \leq s[i+1] - s[i-2] \leq 3b_i +2 (1)3bi?≤s[i+1]?s[i?2]≤3bi?+2(1)
由于題目給定每個店鋪的價格都是正整數
所以還有約束:s[i]?s[i?1]≥1(2)s[i] - s[i-1] \geq 1(2)s[i]?s[i?1]≥1(2)
得到了不等式約束,并且都是作差的形式,所以這是一道差分約束的題目。那么就要往spfa求最短路和最長路的角度去想。這里要求字典序最小的值,按照套路,這里要用最長路,所以三角不等式為:
dist[b]≥dist[a]+cdist[b] \geq dist[a] + cdist[b]≥dist[a]+c
對應的是a到b有一條權值為c的邊。
所以我們對上面的(1)和(2)不等式約束進行變形,同時得到點、邊權的關系:
(1)式可以拆成2個不等式:
s[i+1]≥s[i?2]+3bis[i+1] \geq s[i-2] + 3b_is[i+1]≥s[i?2]+3bi?
對應的是i-2這個點到i+1這個點有一條權值為3bi3b_i3bi?的邊
s[i?2]≥s[i+1]?(3bi+2)s[i-2] \geq s[i+1] -(3b_i + 2)s[i?2]≥s[i+1]?(3bi?+2)
對應的是i+1這個點到i-2這個點有一條權值為?(3bi+2)-(3b_i+2)?(3bi?+2)的邊
(2)式對應不等式:
s[i]≥s[i?1]+1s[i] \geq s[i-1] + 1 s[i]≥s[i?1]+1
對應的是i-1這個點到i這個點有一條權值為111的邊
關于差分約束的板子
算法提高課-圖論-差分約束- AcWing 1169. 糖果:spfa求單源最短路、差分約束
這里的最長路指的是,建立一個超級源點0號點,求出所有點到0號點的最長路,為啥求出最長路之后就是我們要求的值呢? 因為這里本質上求的是一系列不等式:
s[i]≥...≥s[0]≥0s[i] \geq... \geq s[0] \geq 0s[i]≥...≥s[0]≥0很多這樣的不等式,我們取它們的交集即可。
每一個這樣的不等式鏈路對應圖中的一個最短路(或者最長路),這里是因為求的是最小值,用的是最長路。
ac代碼
#include<bits/stdc++.h> using namespace std; const int N = 310, M = N * 3; int n, m; int h[N], e[M],w[M], ne[M], idx; int dist[N], q[N]; int b[N]; bool st[N];void add(int a, int b, int c){e[idx] = b, w[idx] =c, ne[idx] = h[a], h[a] = idx ++; }// SPFA求最長路 void spfa(){// 求最長路,需要初始化為-∞memset(dist,-0x3f, sizeof dist);queue<int> q;q.push(0);dist[0] = 0;while(q.size()){auto t = q.front();q.pop();st[t] = false;for(int i = h[t]; ~i; i = ne[i]){int j = e[i];if(dist[j] < dist[t] + w[i]){dist[j] = dist[t] + w[i];if(!st[j]){q.push(j);st[j] = true;}}}} }int main(){memset(h, -1, sizeof h);cin >> n;for(int i = 1; i <= n; i ++) cin >> b[i];//除去端點值需要滿足的條件for(int i = 2; i < n; i ++){add(i -2, i + 1, b[i] * 3 );add( i + 1, i - 2, -(b[i] * 3 + 2));}//端點需要滿足的條件add(0, 2, b[1] * 2), add(2, 0, -(b[1] * 2 + 1));add(n - 2, n, b[n] * 2), add(n, n - 2, -(b[n] * 2 +1));// 所有點都滿足的條件for(int i = 1; i <= n; i ++) add(i - 1, i, 1);// 求最長路spfa();for(int i = 1; i <= n; i ++)// 前綴和求某點的值cout << dist[i] - dist[i - 1] << " ";}題目鏈接
https://www.acwing.com/problem/content/3268/
總結
以上是生活随笔為你收集整理的CSP认证201809-4再卖菜[C++题解]:差分约束、前缀和的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法提高课-图论-负环-AcWing 1
- 下一篇: CSP认证201803-1跳一跳[C++