AcWing 4412. 构造数组
AcWing 4412. 构造数组(三种解法)
思路分析
经分析可得,
\[若a_i = a_j,则 b_i <= b_{i + 1} <= ... <= b_j\\
又\because b_i=b_j\,\,\,\therefore b_i = b_{i + 1} = ... = b_j
\]
所以只需要去统计有多少个这样的区间,然后乘2即可(因为每一个区间都有两种选择)
法一:区间合并
防止umap被卡的小技巧:1. 初始化一个大的长度(见代码);2. here;3.换成map
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353, N = 2e5 + 5;
int n, m, cnt;
pair <int, int> p[N];
void test() {
for (int i = 0; i < m; i ++)
cout << p[i].first << ' ' << p[i].second << endl;
}
signed main () {
unordered_map <int, int> L(300000), R(300000);
cin >> n ;
for (int i = 1; i <= n; i ++) {
int t;cin >> t;
R[t] = i;
if (!L.count(t))
L[t] = i; //左端点只用更新一次
}
int m = 0;
for (auto& [i, v]:L) //高级做法 C++17才能用
p[m ++] = {L[i], R[i]};
sort (p, p + m);
//test();
int l = -1, r = -1;
cnt = m;
for (int i = 0; i < m; i ++) {
if (p[i].first <= r)
r = max (r, p[i].second), cnt --;
else
l = p[i].first, r = p[i].second;
}
int ans = 0;
cnt --;
for (int i = 0; i < cnt; i ++)
ans = ans * 2 % mod;
cout << ans << endl;
}
//bi 到 bj之间的所有数字都要相等
//按照段来划分
法二:离散化 + 差分
染色思想:点坐标 * 2,统计被覆盖的次数,出现0就代表该区间结束,准备进入下一个区间
法三:并查集
这是一种通用思路(并查集常见操作)
把整体视为一个长线段。
每一个区间内的点都向右端点合并,最后就可以统计区间个数了