P9681 幽默的世界。 题解
这个人想不出普及组做法。。。
Solution
不难发现符合题目要求的序列是最后一个数为正数,前面的数都为负数,且全部加起来大于等于 0。
考虑对于每一个右端点,都求出他往前能到的左端点,满足这一段的和大于 0 且只有右端点是正数。
显然前面一段负数的前缀和有单调性,直接二分就可以求。
for(int i = 1; i <= n; i ++) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
if(a[i] <= 0) cnt ++;
else {
int l = 1, r = cnt + 1, tmp = 1;
while(l <= r) {
int mid = l + r >> 1;
if(sum[i] - sum[i - mid] > 0) l = mid + 1, tmp = mid;
else r = mid - 1;
}
ls[i] = tmp;
cnt = 0;
}
}
然后就可以很简单的写出一段 35 分代码。
while(q --) {
int l, r;
int res = 0;
cin >> l >> r;
for(int i = l; i <= r; i ++) {
if(a[i] >= 0)
res += min(i - l + 1, ls[i]);
}
cout << res << '\n';
}
这个式子看起来还不是很好直接优化的样子,我们考虑换一个形式。
for(int i = 1; i <= n; i ++)
p[i] = i - ls[i] + 1;
while(q --) {
int l, r;
int res = 0;
cin >> l >> r;
for(int i = l; i <= r; i ++)
res += i + 1 - max(p[i], l);
cout << res << '\n';
}
前面 \(\sum_{i=l}^{i=r} i + 1\) 是好算的,只需要求后面这段就好。
求后面这个需要用到的有:
- 区间 \([l, r]\) 中大于等于 \(l\) 的个数。
- 区间 \([l, r]\) 中大于等于 \(l\) 的数之和。
直接上主席树就可以做了。
#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 2e5 + 5, INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
int n, q;
int a[N], ls[N], s[N], p[N];
LL sum[N];
struct SegT {
int l, r;
PII val;
#define l(x) tr[x].l
#define r(x) tr[x].r
#define val(x) tr[x].val
} tr[N << 5];
int rt[N], idx;
void pushup(int x) {
val(x).fi = val(l(x)).fi + val(r(x)).fi;
val(x).se = val(l(x)).se + val(r(x)).se;
}
void build(int &x, int l, int r) {
x = ++ idx;
tr[x] = {l, r};
if(l == r) return;
int mid = l + r >> 1;
build(l(x), l, mid), build(r(x), mid + 1, r);
}
void insert(int &x, int lst, int l, int r, int v) {
x = ++ idx;
tr[x] = tr[lst];
if(l == r) {
val(x).fi += v;
val(x).se ++;
return;
}
int mid = l + r >> 1;
if(v <= mid) insert(l(x), l(lst), l, mid, v);
else insert(r(x), r(lst), mid + 1, r, v);
pushup(x);
}
PII query(int x, int y, int l, int r, int nl, int nr) {
if(nl <= l && r <= nr) {
return {val(y).fi - val(x).fi, val(y).se - val(x).se};
}
int mid = l + r >> 1;
PII res;
if(nl <= mid) res = query(l(x), l(y), l, mid, nl, nr);
if(nr > mid) {
auto t = query(r(x), r(y), mid + 1, r, nl, nr);
res.fi += t.fi;
res.se += t.se;
}
return res;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> q;
int cnt = 0;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
if(a[i] <= 0) cnt ++;
else {
int l = 1, r = cnt + 1, tmp = 1;
while(l <= r) {
int mid = l + r >> 1;
if(sum[i] - sum[i - mid] > 0) l = mid + 1, tmp = mid;
else r = mid - 1;
}
ls[i] = tmp;
cnt = 0;
}
}
for(int i = 1; i <= n; i ++)
s[i] = s[i - 1] + ls[i], p[i] = i - ls[i] + 1;
build(rt[0], 1, n);
for(int i = 1; i <= n; i ++)
insert(rt[i], rt[i - 1], 1, n, p[i]);
while(q --) {
int l, r;
LL res = 0;
cin >> l >> r;
if(l == 1) cout << s[r] - s[l - 1] << '\n';
else {
auto t = query(rt[l - 1], rt[r], 1, n, l, n);
res = (l + r) * (r - l + 1) / 2 + (r - l + 1);
res -= t.fi;
res -= (r - l + 1 - t.se) * l;
cout << res << '\n';
}
}
return 0;
}

浙公网安备 33010602011771号