1 条题解
-
0
I. 可微波子序列 详细题解
问题重述
给定长度为 的数组 ,值域 。对于每一对 (),定义 为最长的可微波子序列的长度,其中子序列只包含 和 ,且相邻元素不同(即交替出现)。求所有 的和。
关键观察
-
值是否出现:若一个值在 中至少出现一次,则称其为出现值,否则为未出现值。设出现值的总数为 。
- 若 均未出现,则 。
- 若恰有一个出现,则 (因为可以取单个出现的那个值)。这样的对共有 个。
- 若两者均出现,则需要进一步计算。
-
两个值均出现的情况:对于固定的 ,考虑原数组中所有 和 按原顺序构成的序列。该序列中相邻不同的对数记为 ,则最长交替子序列的长度为 。因为每对相邻的不同值可以保留,而连续相同的值只能保留一个。因此:
其中 等于满足以下条件的相邻位置对 ()的个数:
- 且 ;
- 区间 内没有其他 或 (即 和 在过滤后的序列中相邻)。
-
总和的分解:
$$\text{答案} = \underbrace{c(M-c)}_{\text{恰一个出现}} \;+\; \underbrace{\binom{c}{2}}_{\text{两个出现的基础1}} \;+\; \underbrace{\sum_{x<y} p(x, y)}_{\text{所有相邻不同对的总数}} $$因此问题转化为计算所有不同的出现值对 的相邻不同对总数。
计算相邻不同对总数
对于每个位置 ,设 ,并设 为 上一次出现的位置(若未出现过则为 )。考虑所有之前出现过的值 ,且 的最后一次出现位置为 。若 ,则 构成一个合法的相邻不同对(因为区间 内没有 和 )。这是因为 的最近一次出现就是 ,而 的最近一次出现 ,所以中间不会出现 。
因此,对于当前 ,贡献的合法对数量为:
$$\text{其他出现值的个数} - \#\{\text{last}[u] < \text{last}[v]\} $$其中“其他出现值”指的是已经出现过且不等于 的值。
维护两个变量:
- :当前已经出现过的不同值的个数(即 的 的数量)。
- 一个树状数组(Fenwick Tree),记录每个最后出现位置上的标记(值为 ),支持单点更新和前缀和查询。
遍历数组 :
- (若 未出现过则为 )
- (其他出现值的个数)
- $less = \begin{cases} \text{BIT.query}(pre-1) & \text{if } pre > 0 \\ 0 & \text{otherwise} \end{cases}$
- ,累加到总答案 中。
- 然后更新:
- 若 ,则 (移除旧位置)
- (添加新位置)
- 若 ,则 (新值出现)
遍历结束后, 即为所有相邻不同对的总数 。
最终答案
设 (最终出现值的总数),则
时间复杂度 ,空间 ,满足 。
参考代码
#include <bits/stdc++.h> using namespace std; using ll = long long; // 树状数组 struct BIT { int n; vector<int> bit; BIT(int sz) : n(sz), bit(sz + 2, 0) {} void add(int idx, int delta) { for (; idx <= n; idx += idx & -idx) bit[idx] += delta; } int sum(int idx) { int res = 0; for (; idx > 0; idx -= idx & -idx) res += bit[idx]; return res; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, M; cin >> N >> M; vector<int> A(N); for (int i = 0; i < N; ++i) cin >> A[i]; vector<int> last(M + 1, 0); BIT bit(N + 5); ll total_pairs = 0; int cur = 0; // 当前出现过的不同值的个数 for (int i = 1; i <= N; ++i) { int v = A[i-1]; int pre = last[v]; int other = cur - (pre != 0 ? 1 : 0); int less = (pre > 0 ? bit.sum(pre - 1) : 0); total_pairs += other - less; // 更新 if (pre != 0) bit.add(pre, -1); bit.add(i, 1); last[v] = i; if (pre == 0) ++cur; } ll c = cur; ll ans = total_pairs + c * (M - c) + c * (c - 1) / 2; cout << ans << '\n'; return 0; } -
- 1
信息
- ID
- 7171
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者