【codeforces思维题】前缀和的巧妙应用(2053B)
【CF思维题】前缀和的巧妙应用(2053B)
Problem - 2053B - Codeforces
给定 n n n个印象,每个印象对应一个区间,印象可以是该区间中任意一个数字。假设第 i ( 1 ≤ i ≤ n ) i(1 \leq i \leq n) i(1≤i≤n)个印象选择的数字是 n u m i num_i numi,当且仅当对于所有 j ( 1 ≤ j ≤ n & & j ≠ i ) j(1 \leq j \leq n \ \&\&\ j \neq i) j(1≤j≤n && j=i),都有 n u m j ≠ n u m i num_j \neq num_i numj=numi,可以认为第 i i i个印象是唯一的。考虑所有印象,若该印象可以是唯一的,输出 1 1 1否则输出 0 0 0
解法:
-
对于每一个 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n ,对于每个 l i ≤ x ≤ r i l_i \leq x \leq r_i li≤x≤ri ,我们要检查每个印象在 x x x处是否唯一。注意,对于每个 j ≠ i j \neq i j=i ,若 l j ≠ r j l_j \neq r_j lj=rj ,我们总是可以将 w j w_j wj 换成不同的值。所以当且仅当存在一个 1 ≤ j ≤ n 1 \leq j \leq n 1≤j≤n 且 j ≠ i j \neq i j=i ,使得 l j = r j = x l_j = r_j = x lj=rj=x ,这是不可能的。
-
让我们将 a i a_i ai记录为满足 1 ≤ k ≤ n 1 \leq k \leq n 1≤k≤n 且 l k = r k = i l_k = r_k = i lk=rk=i 时,不同 k k k 的数量。(这个很好统计,不妨用桶或 m a p map map 等统计 l k ( l k = r k ) l_k(l_k = r_k) lk(lk=rk) 这个数字的出现次数)。如果 l i ≠ r i l_i \neq r_i li=ri ,那我们说印象 i i i不能被唯一化当且仅当对于所有 l i ≤ k ≤ r i , a k ≥ 1 l_i \leq k \leq r_i,a_k \geq 1 li≤k≤ri,ak≥1 ;如果 l i = r i l_i = r_i li=ri,当且仅当 a l i ≥ 2 a_{l_i} \geq 2 ali≥2 时,它不能唯一化。
-
以上内容可以在前缀和中快速检查。我们要在一个区间中检查该区间中所有数字是否都可以满足某个性质时,不妨将该数轴上的数字标记。若标记成 1 1 1,则满足;标记成 0 0 0,则不满足。随后求一遍前缀和。若 s u m [ r ] − s u m [ l − 1 ] = 0 sum[r] - sum[l - 1] = 0 sum[r]−sum[l−1]=0,证明了该区间的和是 0 0 0,意味着区间中任意一个数字都不满足该性质;反之,则说明该区间有数字可以满足该性质。
-
考虑区间上问题时,不妨从前缀和角度思考问题。
#include <bits/stdc++.h>
using namespace std;typedef pair<int, int> pII;
#define x first
#define y secondvoid solve() {int n;cin >> n;vector<pII> segs;map<int, int> cnt;for (int i = 0; i < n; i ++) {int l, r;cin >> l >> r;segs.push_back({l, r});if (l == r) {cnt[r] ++;}}vector<int> f(2 * n + 10, 1);f[0] = 0;for (auto& [u, v] : cnt) {if (v >= 1) f[u] = 0;}for (int i = 1; i <= 2 * n; i ++) {f[i] += f[i - 1];}for (int i = 0; i < segs.size(); i ++) {int l = segs[i].x, r = segs[i].y;if (l == r) {if (cnt[r] == 1) cout << '1';else cout << '0';} else {if (f[r] - f[l - 1] == 0) cout << '0';else cout << '1';}}cout << endl;}int main() {int t;cin >> t;while (t --) {solve();}return 0;
}