2022.10.18 总结
1. 逐月 P5074
题意
有 \(n\) 头奶牛,第 \(i\) 头奶牛的位置在 \(w_i\)。
每头奶牛要么有斑点,要么没有。
对于在位置 \(i\) 的奶牛,它有没有斑点取决于在 \(n\) 头奶牛中和它距离最近的那头奶牛,如果那头奶牛有斑点,它就有,否则没有。
如果有很多头奶牛到它的距离最近,那么只要那些奶牛中有一头有斑点即可。
现在,位置 \(a\) 到位置 \(b\) 上每个位置都有一头奶牛,请问这些奶牛中有多少头奶牛有斑点。
思路
100 分
如果在位置 \(1\) 上有一头奶牛,位置 \(3\) 上面有一头奶牛,并且他们中间没有奶牛,那么位置 \(1 \sim 3\) 的奶牛是否有斑点就只和这两头奶牛有关。
所以,可以只枚举 \(n\) 头奶牛计算答案。
那么就要开始分类讨论了。
假设当前选的两头相邻奶牛编号为 \(i\),\(i + 1\)。
-
\(i\) 和 \(i + 1\) 都有斑点,直接把区间内的所有奶牛全部加起来。
-
\(i\) 和 \(i + 1\) 都没有斑点,直接进入下一次循环。
-
\(i\) 有斑点,\(i + 1\) 没有,从他们的等分点往右的都是斑点牛。
-
\(i\) 没有,\(i + 1\) 有斑点,从他们的等分点往左的都是斑点牛。
直接模拟即可。
但是有一个小细节:这 \(n\) 头奶牛可能会被算两遍,所以要先预处理出这 \(n\) 个点中可行的点,在模拟时忽略这 \(n\) 个点即可。
时间复杂度
枚举 \(n\) 头奶牛,\(O(n)\)。
空间复杂度
记录所有奶牛,\(O(n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
int n, a, b, cnt;
string s;
struct cow{
bool f;
int w;
} c[N];
bool cmp(const cow &i, const cow &j){ // 按照位置排序
return i.w < j.w;
}
void F(int l, int r){ // 更新斑点牛数量
cnt += max(0, min(r, b) - max(l, a) + 1);
}
int main(){
freopen("learning.in", "r", stdin);
freopen("learning.out", "w", stdout);
cin >> n >> a >> b;
int m = 0;
for (int i = 1; i <= n; i++) {
cin >> s >> c[i].w;
c[i].f = (s == "S");
cnt += (c[i].f && c[i].w >= a && c[i].w <= b); // 预处理出可行的斑点奶牛
}
sort(c + 1, c + n + 1, cmp);
c[0] = {c[1].f, 1};
c[n + 1] = {c[n].f, int(1e9)};
for (int i = 0; i <= n; i++) {
if (c[i].f && c[i + 1].f) {
F(c[i].w + 1, c[i + 1].w - 1);
} else if (c[i].f) {
F(c[i].w + 1, (c[i].w + c[i + 1].w) / 2);
} else if (c[i + 1].f) {
F((c[i].w + c[i + 1].w + 1) / 2, c[i + 1].w - 1);
}
}
cout << cnt;
return 0;
}