题解:P12391 「RiOI-6」帝国少女
Register_int · · 题解
直接对一个子段暴力是典题。若
然后考虑原题,你需要对所有子段求和。对于
- 作为一段前缀出现。
- 作为一段后缀出现。
- 完整出现。
- 自己把子段包含住。
都是好统计的,可以做到线性。难的是
所以你将所有
其中一个验题人认为本题是紫题并提出了一个分块做法。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
int n, m, a[MAXN], s[MAXN]; ll sum, ans;
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
if (m == 2) {
for (int i = 1; i <= n; i++) a[i]--, (i & 1) && (a[i] ^= 1);
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + (a[i] ? 1 : -1);
sort(s, s + n + 1);
for (int i = 1; i <= n; i++) ans += (ll)i * (n - i + 1);
for(int i = 0; i <= n; i++) ans -= (ll)s[i] * i - sum, sum += s[i];
printf("%lld", ans >> 1); return 0;
}
for (int i = 0, k = 0; i <= n; i++) {
if (a[i] == a[i + 1]) { k++; continue; }
for (int j = 1; j < k; j++) ans += (ll)j / 2 * (k - j + 1);
ans += (ll)k / 2 * (i - k + 1) * (n - i + 1);
for (int j = 1; j < k; j++) ans += (ll)j / 2 * (n - k);
k = 1;
}
printf("%lld", ans);
}