专栏文章
题解:P10764 [BalticOI 2024] Wall
P10764题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minr95uv
- 此快照首次捕获于
- 2025/12/02 07:03 3 个月前
- 此快照最后确认于
- 2025/12/02 07:03 3 个月前
考虑分别求 和 ,而显然 ,仅需考虑 。
我们注意到 ,于是我们考虑从 到 枚举 ,检查是否 。而我们知道 ,于是 当且仅当 且 。
如果存在 和 都满足 ,那么显然任意选都能满足 ,于是贡献即为 。记最小的满足 的 为 ,最大的为 ,那么 都有 的贡献。我们考量 ,此时右侧仍然无需在意,但是左侧必须有一个 。我们记 ,那么贡献即为任意选的方案数减去 左侧选不出任何一个 的方案数,即 。对称地, 的贡献即为 。
如果不存在满足上文条件的 ,那么 左侧要选出一个 ,右侧要选出一个 ,方案数即为
观察形式,综上,我们得出结论:
- 无论何时, 总有贡献 。
- 如果不存在 使得 ,那么额外贡献 。
- 如果不存在 满足该条件,额外贡献 。
- 特别地,如果 2 和 3 同时满足,额外贡献 。
直接使用线段树维护 和上述一些值即可做到 ,但是实现并不优美。
我们考虑对于线段树上一个节点 维护 ,分别表示仅考虑 的子串时上文中第 4 条的值、第 2、3 条 的值之和。考虑记 ,那么显然 。我们又注意到满足贡献条件时 ,而 在 中维护,可以在
pushup 中将左儿子的贡献乘到右儿子上合并,于是我们可以对叶节点记 ,非叶节点有 。类似地也有 。这样我们只需要修改 即可,仅需维护一棵单点修改、全局查询的线段树,时间复杂度 。
Code:
CPP#include<bits/stdc++.h>
#define mem(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxn = 5e5 + 10, mod = 1e9 + 7;
int n, res = 0;
int a[maxn], b[maxn], pwr[maxn], val[maxn];
vector<int> tmp, ad[maxn << 1];
template<typename Tp_x, typename Tp_y>
inline int mod_add(Tp_x x, Tp_y y){
return x += y, x >= mod ? x -= mod : x;
}
template<typename Tp_x, typename Tp_y>
inline int self_mod_add(Tp_x &x, Tp_y y){
return x = mod_add(x, y);
}
template<typename Tp, typename... Arg>
inline int mod_add(Tp x, Arg ...args){
return x += mod_add(args...), x >= mod ? x -= mod : x;
}
namespace segtree{
struct{
int l, r, pre, suf, val;
} tree[maxn << 2];
inline void pushup(int index){
tree[index].pre = mod_add(tree[index << 1].pre, (long long)tree[index << 1 | 1].pre * tree[index << 1].val % mod);
tree[index].suf = mod_add(tree[index << 1 | 1].suf, (long long)tree[index << 1].suf * tree[index << 1 | 1].val % mod);
tree[index].val = (long long)tree[index << 1].val * tree[index << 1 | 1].val % mod;
}
inline void build(int index, int l, int r){
tree[index].l = l, tree[index].r = r;
if (l == r){
return;
}
const int mid = l + r >> 1;
build(index << 1, l, mid), build(index << 1 | 1, mid + 1, r);
}
inline void modify(int index, int x, int k){
if (tree[index].l == tree[index].r){
return tree[index].pre = (long long)pwr[n - x] * k % mod, tree[index].suf = (long long)pwr[x - 1] * k % mod, tree[index].val = k, void();
}
const int mid = tree[index].l + tree[index].r >> 1;
modify(index << 1 | x > mid, x, k), pushup(index);
}
}
using namespace segtree;
inline int pos(int x){
return lower_bound(tmp.begin(), tmp.end(), x) - tmp.begin() + 1;
}
int main(){
scanf("%d", &n), build(1, 1, n), pwr[0] = 1;
for (int i = 1; i <= n; i++){
scanf("%d", &a[i]), tmp.push_back(a[i]), pwr[i] = (pwr[i - 1] << 1) % mod;
}
for (int i = 1; i <= n; i++){
scanf("%d", &b[i]), tmp.push_back(b[i]);
self_mod_add(res, mod - (long long)pwr[n - 1] * mod_add(a[i], b[i]) % mod);
}
sort(tmp.begin(), tmp.end()), tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end()), self_mod_add(res, (long long)tmp[0] * n % mod * pwr[n] % mod);
for (int i = 1; i <= n; i++){
ad[pos(a[i])].push_back(i), ad[pos(b[i])].push_back(i);
}
for (int i = 2; i <= tmp.size(); i++){
for (auto x: ad[i - 1]){
modify(1, x, ++val[x]);
}
self_mod_add(res, (long long)(tmp[i - 1] - tmp[i - 2]) * mod_add((long long)n * pwr[n] % mod, mod - tree[1].pre, mod - tree[1].suf, (long long)n * tree[1].val % mod) % mod);
}
printf("%d", res);
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...