1、卖菜
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
int cnt = 0, sum = 0;
if (a[i - 1]) cnt++, sum += a[i - 1];
if (a[i]) cnt++, sum += a[i];
if (a[i + 1]) cnt++, sum += a[i + 1];
cout << sum / cnt << " ";
}
return 0;
}
2、买菜
#include <iostream>
#include <algorithm>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 2010;
int n;
PII p[N], q[N];
int get(PII a, PII b) {
if (a.y < b.x || b.y < a.x) return 0;
return min(a.y, b.y) - max(a.x, b.x);
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;
for (int i = 0; i < n; i++) cin >> q[i].x >> q[i].y;
int res = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
res += get(p[i], q[j]);
cout << res << endl;
return 0;
}
3、元素选择器
4、再卖菜(差分约束)
假设存在两个序列 a 1 , a 2 , ⋯ , a n a_1,a_2, \cdots, a_n a1,a2,⋯,an 和 b 1 , b 2 , ⋯ , b n b_1, b_2, \cdots, b_n b1,b2,⋯,bn。
先考虑 b b b 序列中的一般情况,即 b i = a i − 1 + a i + a i + 1 3 ( i ∈ [ 2 , n − 1 ] ) b_i = \frac{a_{i-1} + a_i + a_{i + 1}}{3}\ (i\in[2,n-1]) bi=3ai−1+ai+ai+1 (i∈[2,n−1]) 的时候 ,这里之前可以预处理处序列 a a a 的前缀和 S S S 以方便求值,那么 b i = ⌊ S i + 1 − S i − 2 3 ⌋ b_i = \left \lfloor \frac{S_{i+1} - S_{i-2}}{3} \right \rfloor bi=⌊3Si+1−Si−2⌋ ,那么就存在关系: 3 b i ≤ S i + 1 − S i − 2 ≤ 3 b i + 2 3b_i \le S_{i+1} - S_{i-2} \le 3b_i + 2 3bi≤Si+1−Si−2≤3bi+2又根据题目可知 a i ≥ 1 a_i \ge 1 ai≥1,因此还存在条件 S i − S i − 1 ≥ 1 S_i - S_{i-1} \ge 1 Si−Si−1≥1。
综上:题目转换为在满足条件 { 3 b i ≤ S i + 1 − S i − 2 ≤ 3 b i + 2 S i − S i − 1 ≥ 1 \begin{cases} &3b_i \le S_{i+1} - S_{i-2} \le 3b_i + 2\\ &S_i - S{i-1} \ge 1\\ \end{cases} {3bi≤Si+1−Si−2≤3bi+2Si−Si−1≥1的前提下求出 S i ( i ∈ [ 1 , n ] ) S_i(i\in[1, n]) Si(i∈[1,n])的值。
因为求解最小值,所以应该求解最长路,其差分格式对应于 d b ≥ d a + c d_b \ge d_a + c db≥da+c,表示一条从 a a a 指向 b b b 且权值为 c c c 的边。
将所有的不等式转化成差分的格式:
{
S
i
+
1
≥
S
i
−
2
+
3
b
i
S
i
−
2
≥
S
i
+
1
−
(
3
b
i
+
2
)
S
i
≥
S
i
−
1
+
1
\begin{cases} &S_{i+1} \ge S_{i-2} + 3b_i\\ &S_{i-2} \ge S_{i+1} - (3b_i + 2)\\ &S_i \ge S_{i-1} + 1\\ \end{cases}
⎩
⎨
⎧Si+1≥Si−2+3biSi−2≥Si+1−(3bi+2)Si≥Si−1+1注意这个题目存在一个绝对值
S
0
=
0
S_0 = 0
S0=0。
因为差分约束可以求出每个元素的最小值,那么也就相当于求解出了字典序的最小值。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 310, M = N * 3; // 有三个不等式,要建三条边
int n;
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++;
}
void spfa() {
int hh = 0, tt = 1;
memset(dist, -0x3f, sizeof dist);
dist[0] = 0;
q[0] = 0;
while (hh != tt) {
int t = q[hh++];
if (hh == N) hh = 0;
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[tt++] = j;
if (tt == N) tt = 0;
st[j] = true;
}
}
}
}
}
int main() {
cin >> n;
memset(h, -1, sizeof h);
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] << ' '; // dist[i] 对应于 S[i]
return 0;
}