[ARC128D] Neq Neq 题解
不难考虑设 \(f_i\) 表示现在处理了前 \(i\) 个数,第 \(i\) 个数必选得到的方案数。由于 \(a_n\) 不可能被删掉(需要一个 \(a_{n+1}\)),所以答案即为 \(f_n\)。
对 \(f_i\),我们考虑前一个被保留的数 \(j\),问题转化成被 \(i,j\) 夹住的一段连续的数可不可以全部删掉,分类讨论:
- \(j=i-1\):啥都没夹,当然能全删了。
- 有两个相同颜色的数相邻:肯定不行,因为这两个数互相锁死了。
- 相邻数互不相等:
- 有两种颜色:那么只可能形如
b|abababab|a,这种情况能够全删只可能是a|b|a。因为只要中间那段长度大于 \(1\) 后,随便删掉哪个数都会变成第二种情况。 - 有三种及以上颜色:那么最坏情况下也肯定形如
a|babacabab|a,我们单独把c拿出来,可以发现,我们只要以c为中心,不断地消除左边和右边的数即可。
- 有两种颜色:那么只可能形如
我们现在就能判断一段数能不能被删了,现在只剩下一个问题:怎么快速寻找 \(j\)?
由于不能有两个相同颜色的数相邻,所以在扫描序列的过程中,只要出现了 \(a_{i-1}=a_i\),那么之后的数就不能扫描到 \(i-1\),因为扫到那里就会出现相邻同颜色,于是我们解决了这个问题。
至于判断颜色种数,你直接双指针不就完了。/cf/cf/cf。
#include <atcoder/all>
#include <iostream>
using namespace std;
using LL = atcoder::modint998244353;
const int kN = 2e5 + 1;
int n, a[kN], c[kN], cc;
LL f[kN], s[kN];
void A(int x) { cc += !c[a[x]]++; }
void D(int x) { cc -= !--c[a[x]]; }
int main() {
ios_base::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
f[1] = s[1] = 1, A(1);
for (int i = 2, p = 0, j = 1; i <= n; ++i) {
f[i] += f[i - 1];
if (i > 2 && a[i - 2] == a[i] && a[i - 1] != a[i]) {
f[i] += f[i - 2];
}
A(i);
if (a[i - 1] == a[i]) {
p = i - 1;
s[i] = s[i - 1] + f[i];
continue;
}
for (; cc > 2; D(j++)) {
}
if (cc == 2 && j > p) {
f[i] += s[j - 1] - s[p];
}
s[i] = s[i - 1] + f[i];
}
cout << f[n].val();
return 0;
}

浙公网安备 33010602011771号