NOIP2025题解
NOIP 2025
A. candy
答案一定是选择一些 \(x+y\),然后选择一些编号不同的 \(x\)。
所以贪心选择 \(x\),按 \(x\) 排序,选择一段前缀。
\(x+y\) 的选法就是找到最小的一直选。
按 \(x\) 排序,设 \(v=\min x_i+y_i,pre_i=\sum_{j\leq i}x_j\):
答案就是 \(\max_{i\in[0,n],pre_i\leq m} i+2\lfloor\frac{m-pre_i}{v}\rfloor\)。
B. sale
令 \(b_iw_i=a_i\)。
考虑情况不合法当且仅当:
找到三个位置 \(i,j,k\) 使得 \(a_i>a_j+a_k\),且 \(2a_j>a_i(2a_k<a_i)\)。
此时 \(a_i>a_j>a_k\)。不妨先把 \(a\) 从小到大排序。此时 \(i>j>k\)。
此时如果 \(w_i=2,w_j=w_k=1\),且按 \(b\) 排序后 \(b_j\) 和 \(b_i\) 之间都是 \(w=2\),\(b_i\) 和 \(b_k\) 之间 \(w=2\)。
并且 \(a\geq a_i\) 的 \(w\) 之和(不包括 \(w_i\))是 \(m-1\)。
那么贪心策略会选择 \(a_j+a_k\),但是最优做法是选择 \(a_i\)。
考虑对上面的情况计数。
“排序后”这个条件太麻烦了。考虑排序前要求哪些位置 \(w=2\)。
观察一下,发现对于 \(u\in (k,j)\),都要求 \(w_u=2\),否则不合法。
对于 \(u\in (j,n]\setminus \{i\}\) 的,分成两部分 \((j,i)(i,n]\),第一部分 \(w=1\) 才会被选中,第二部分一定会被选中。
于是问题就变成,第一部分一开始 \(w\) 没有贡献,第二部分一开始 \(w=1\),两部分每个位置都可以贡献 \(+1\),问总贡献 \(m-2\) 的方案数。
左侧大小 \(i-j-1\),右侧 \(n-i\),于是方案数就是 \(\binom{n-j-1}{m-2-(n-i)}\)。
然后对于 \(u\in[1,k)\),\(w\) 随便。方案数 \(2^{k-1}\)。
于是答案就是 \(\sum_{i\geq 1}\sum_{j\geq 1}\left(\binom{n-j-1}{m-2-(n-i)}\sum_{k\geq 0} 2^{\max(0,k-1)}[a_j+a_k<a_i,2a_j>a_i]\right)\)。
\(\sum_k\) 可以直接变成 \(2^{\sum_{k\geq 1}[a_j+a_k<a_i]}\)。
所以就是 \(\sum_{i\geq 1}\sum_{j\geq 1,2a_j>a_i}\left(\binom{n-j-1}{m-2-(n-i)}2^{\sum_{k\geq 1}[a_j+a_k<a_i]}\right)\)。
对于 \(k\),合法的是一段前缀。且随着 \(j\) 单调。所以直接暴力移动找,均摊线性。
复杂度 \(\mathcal{O}(n^2)\)。
C. tree
很厉害。
考虑 \(u\) 被子树内的点贡献,是一个比较常见的暴力。
通过延迟决策,设计 dp \(f(i,j,k)\) 表示 \(i\) 的 \(\text{mex}=j\),子树内有 \(k\) 个点还没有决策的最优答案。
因为 \(j\leq sz_i\),转移复杂度也不超过背包,所以按照树上背包的复杂度分析,是不超过 \(\mathcal{O}(n^3)\) 的。
但是很可惜这个暴力不太好优化。
但是这个 dp 思路是可以给我们启发的:考虑 dp 的转移过程,发现 \(j\) 只和子树的 \(\max j\),以及消耗了多少 \(k\) 有关系。
也就是我们可以得到树的一个链剖分:把子树的 \(\max j\) 作为重儿子。有什么用呢。
换一种方式思考:
考虑反过来贡献,考虑一个点会对祖先造成什么贡献。
发现一个点会对祖先的一条链造成贡献。
继续思考这个特殊性质。结合上面的暴力做法,我们发现,这种东西相当于对树进行上述链剖分,然后一个点 \(u\) 的贡献就是从某个点 \(v\in anc(u)\) 到这个点的链顶 \(top_v\),对应 \(k\) 在 \(v\) 处的消耗。
所以 \(u\) 需要找某个祖先 \(i\),然后贡献到链顶 \(top_i\)。贡献是 \(dep(i)-dep(top_i)+1\)。
上面一堆都是为了推出这个性质:即 \(u\) 的贡献是 \(t_u=\max_{i\in anc(u)}dep(i)-dep(top_i)+1\)。
I.
然后根据这个,我们可以设计出一个 \(O(nm^2)\) 的 dp:\(f(i,j,k)\) 表示 dp 到 \(i\),钦定 \(t_i=j,dep(i)-dep(top_i)+1=k\)。
转移的时候,枚举重儿子 \(u\),有 \(f(i,j,k)=j+\max_{u\in son(i)}f(u,\max(j,k+1),k+1)+\sum_{v\neq u\in son(i)}f(v,j,1)\)。
考虑对这个 dp 进一步优化。
令 \(dis_i\) 为 \(i\) 子树的高度。
我们发现,如果 \(j-k>dis_i\),那么对于子树内的任意一点,都有 \(k<j\),那么都不如贡献到 \(j\),所以 \(k\) 更大和 \(k=j+dis_i\) 是等价的。故 \(k\leq j+dis_i\)。
为了方便转移,我们不妨令 \(k'=j-k\leq dis_i\)。设新状态为 \(f'(i,j,k')\)。
于是转移变成:
- \(k'=0\):\(f'(i,j,k')=j+\max_{u\in son(i)}f'(u,j+1,0)+\sum_{v\neq u\in son(i)}f'(v,j,1)\)
- \(k'\neq 0\):\(f'(i,j,k')=j+\max_{u\in son(i)}f'(u,j,k'-1)+\sum_{v\neq u\in son(i)}f'(v,j,1)\)
注意到 \(k'\leq dis_i\)。且转移(绝大部分)跟高度有关,这让我们想到了长剖优化 dp。
于是直接上套路。转移有点小麻烦。复杂度 \(\mathcal{O}(nm)\)。
II.
根据性质的另一种做法。
注意到对于 \(k<j\) 的部分,贡献都是 \(j\),所以我们考虑直接跳过 \(k<j\) 的中间状态,直接转移整条链。
对于 \(i\),重链的状态不超过 \(sz_i\) 种。注意到统计到的点对数量其实是 \(\sum_{i\in leaf} dep_i=\mathcal{O}(nm)\) 的,所以只要能 \(\mathcal{O}(\log)\) 之内转移就行了。
考虑设计 dp 状态。
\(f(i,j)\) 表示,\(t_i=dep(i)-dep(top_i)+1=j\) 的子树答案。
然后没法直接转移,问题是轻儿子的信息不足。
于是 \(g(i,j)\) 表示 \(i\) 为重链顶,\(t_i=j\) 的子树答案。
分别对应 I. 中的 \(f(i,j,j)\) 和 \(f(i,j,1)\)。相当于把 \(k=j\to 1\) 中间的步骤直接跳过了。
\(f\) 的转移比较简单,要么是轻儿子贡献为 \(g(u,0)\),要么是重儿子 \(f(v,j+1)\)。
也就是 \(f(i,j)=\sum_{u\in son(i)}g(u,0)+\max_{v\in son(i)} f(v,j+1)-g(v,0)\)。
然后 \(g\) 转移,考虑把重链分成 \(dep-dep_i+1\leq j\) 和 \(>j\) 两部分。
就是枚举 \(dep_u-dep_i=j\):
\(g(i,j)=j^2+\max_{u\in tr(i),dep_u-dep_i=j}\left(f(u,j+1)+\sum_{fa_k\in path(i,fa_u)}g(k,j)\right)\)。
其中 \(j^2\) 就是 \(dep-dep_i+1\leq j\) 里面每个点 \(j\) 的贡献。
如果不存在就是 \(g(i,j)=j+\sum_{u\in son(i)}g(u,j)\)。
然后后面那个 \(\sum_k\) 使用数据结构,把 \(g(k,j)\) 贡献到其所有兄弟的子树内。做子树加,然后查询就是单点查询。可以使用树状数组维护。
复杂度 \(\mathcal{O}(nm\log n)\)。
D. query
不会数据结构啊。
I.
考虑把区间看做点 \(l_i,r_i\) 放到二维平面上。
问题是给出 \(L_j,R_j\),求 \(\max_{1\le l\le i\le r\le n}\{\sum_{i=l}^{r} a_i\mid L_j\le r-l+1\le R_j\}\)。
在二维平面上,我们发现,要求的其实是 \(l\leq i\),且在 \(r=l+L\) 和 \(r=l+R\) 两条直线之间的点的最大值。
这是一个梯形。并且可以拆成平行四边形和一个等腰直角三角形。
对于平行四边形,我们知道对于已知的 \(l\),要求的是 \(r\in [l+L,l+R]\) 内点的最大值。使用 ST 表加上单调队列可以对每个 \(i\) 都算出来。
对于三角形,不太好直接算,于是拆成两个平行四边形(做法相同),以及一个对应直角的正方形。
正方形就是 \(l\in [i-d,i],r\in [i,i+d]\) 内 \((l,r)\) 的最大值,两侧分别求,然后并起来就好了。
II.
考虑 \(L=R\) 的特殊性质。
我们发现,使用单调队列即可。
考虑 \(L\neq R\) 会漏掉那些情况。
我们发现对于 \(i\) 加入后,会被其后继 \(nx_i\) 弹出队列。此时 \([i,nx_i)\) 这部分元素,可能还可以被某些 \([i,r]\) 贡献。
具体的,当 \(r=nx_i+i-1\) 时,将 \(i\) 弹出。在 \(r=i+R-1\) 后,变为不合法。
于是贡献就是 \(\max_{i\in [nx_i+i-1,i+R-1]}pre_i\)。
然后问题变成要对两组区间取 \(\max\):
- 一组互相不包含的区间,也就是贪心用单调队列得到的结果。
- 一些 \([i,nx_i)\)。这种东西发现除包含外不交。刻画值大小的包含关系的就是笛卡尔树。所以在树上 dfs 把标记下传就可以了。
III.
考虑特殊性质 \(L>n/2\)。
此时所有区间会经过中点。进一步拓展,对于长度 \(\in [d,2d)\) 来说,至少会经过一个间隔为 \(d\) 的点,最多两个。
当然,有丰富数据结构经验的应该可以直接跳过所有特殊性质,意识到可以通过撒关键点来做。
然后发现 \([d,2d)\) 可以通过值域倍增分块预处理来解决。
也就是预处理 \([2^i,2^{i+1})\),然后两侧的散块通过关键点,讨论是位于被点分割的区间的哪一部分进行计算。
还有一种做法就是,先离散化,然后如果相邻两个位置 \(2b_i<b_{i+1}\) 则插入 \(2b_i\),效果是相同的。
code
A
#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;
template<typename T> void chmin(T& x, T y) { x = min(x, y); }
template<typename T> void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 1e5 + 5;
ll n, a[N], b[N], m;
void solve()
{
cin >> n >> m;
ll mn = 2e18;
rep(i, 1, n) cin >> a[i] >> b[i], chmin(mn, a[i] + b[i]);
sort(a + 1, a + n + 1);
ll s = 0, ans = m / mn * 2;
rep(i, 1, n)
{
s += a[i];
if(s > m) break;
chmax(ans, (m - s) / mn * 2 + i);
}
cout << ans << "\n";
}
signed main()
{
freopen("candy.in", "r", stdin);
freopen("candy.out", "w", stdout);
ios::sync_with_stdio(0);cin.tie(0);
// int c, t; cin >> c >> t;
int t = 1;
while(t --) solve();
return 0;
}
B
#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;
template<typename T> inline void chmin(T& x, T y) { x = min(x, y); }
template<typename T> inline void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 5e3 + 5, p = 998244353;
int n, m, a[N];
inline void add(int &x, ll y) { x = (x + y) % p; }
int fac[N], ifac[N], pw2[N];
ll qpow(ll a, ll b)
{
if(!b) return 1;
return ((b & 1) ? a : 1ll) * qpow(a * a % p, b >> 1) % p;
}
void init()
{
fac[0] = ifac[0] = 1;
rep(i, 1, N - 1) fac[i] = 1ll * fac[i - 1] * i % p;
ifac[N - 1] = qpow(fac[N - 1], p - 2);
per(i, N - 2, 1) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % p;
pw2[0] = 1; rep(i, 1, N - 1) pw2[i] = pw2[i - 1] * 2 % p;
}
ll C(ll a, ll b)
{
if(a < b || a < 0 || b < 0) return 0;
return 1ll * fac[a] * ifac[b] % p * ifac[a - b] % p;
}
void solve()
{
cin >> n >> m;
rep(i, 1, n) cin >> a[i];
sort(a + 1, a + n + 1);
int ans = 0;
per(i, n, 1)
{
int k = 0;
per(j, min(i - 1, n * 2 - m - i + 1), 1) if(a[j] < a[i] && 2 * a[j] > a[i])
{
while(a[k + 1] + a[j] < a[i]) k ++;
add(ans, C(n - j - 1, m - (n - i) - 2) * pw2[k]);
}
}
cout << (pw2[n] - ans + p) % p << "\n";
}
signed main()
{
freopen("sale.in", "r", stdin);
freopen("sale.out", "w", stdout);
init();
ios::sync_with_stdio(0);cin.tie(0);
int c, t; cin >> c >> t;
while(t --) solve();
return 0;
}
C I.
#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;
template<typename T> void chmin(T& x, T y) { x = min(x, y); }
template<typename T> void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 8005, M = 805;
vector<vector<int>> f[N];
vector<int> ad[N], v[N];
int h[M][M];
vector<int> e[N];
int d[N], dis[N], son[N];
int n, m;
void dfs0(int x, int fa)
{
d[x] = d[fa] + 1;
dis[x] = 1; son[x] = 0;
for(int i : e[x]) if(i != fa)
{
dfs0(i, x);
chmax(dis[x], dis[i] + 1);
if(dis[x] == dis[i] + 1)
son[x] = i;
}
}
void dfs(int x, int fa, vector<vector<int>>& fx, vector<int>& adx, int off)
{
int mx = 0;
for(int i : e[x]) if(i != fa && i != son[x])
{
ad[i].assign(m + 2, 0);
f[i].assign(m + 2, vector<int>(dis[i] + 2, 0));
dfs(i, x, f[i], ad[i], 0), chmax(mx, dis[i]);
}
if(son[x]) dfs(son[x], x, fx, adx, off + 1);
if(son[x]) rep(j, 1, d[x]) fx[j][off] = fx[j + 1][off + 1] + adx[j + 1] - adx[j];
rep(i, 0, m + 4) rep(j, 0, mx + 2) h[i][j] = 0;
vector<int> dt(m + 2, 0);
for(int i : e[x]) if(i != fa && i != son[x])
rep(j, 1, d[x])
{
dt[j] += v[i][j] = f[i][j][min(dis[i], j - 1)] + ad[i][j];
}
if(son[x]) rep(j, 1, d[x])
{
v[son[x]][j] = fx[j][min(dis[son[x]], j - 1) + off + 1] + adx[j];
}
for(int i : e[x]) if(i != fa && i != son[x])
{
rep(j, 1, d[x])
{
rep(k, 1, dis[i] + 1)
{
chmax(h[j][k], f[i][j][k - 1] + ad[i][j] - v[i][j] + v[son[x]][j] - fx[j][k + off] - adx[j]);
}
{
chmax(h[j][0], f[i][j + 1][0] + ad[i][j + 1] - v[i][j] + v[son[x]][j] - fx[j + 1][off + 1] - adx[j + 1]);
}
}
}
rep(i, 1, d[x]) adx[i] += i + dt[i];
rep(j, 1, d[x])
rep(k, 0, mx)
fx[j][k + off] += h[j][k];
}
void solve()
{
cin >> n >> m;
rep(i, 1, n)
{
v[i].assign(m + 2, 0);
}
rep(i, 1, n) e[i].clear();
rep(i, 2, n)
{
int fa; cin >> fa;
e[fa].push_back(i);
}
dfs0(1, 0);
f[1].assign(m + 2, vector<int>(dis[1] + 2, 0));
ad[1].assign(m + 2, 0);
dfs(1, 0, f[1], ad[1], 0);
ll ans = f[1][1][0] + ad[1][1];
cout << ans << "\n";
}
signed main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
ios::sync_with_stdio(0);cin.tie(0);
int t; cin >> t;
while(t --) solve();
return 0;
}
C II.
#include<bits/stdc++.h>
#define rep(i, s, h) for(int i = (s); i <= (h); i ++)
#define per(i, s, h) for(int i = (s); i >= (h); i --)
using namespace std;
template<typename T> void chmin(T& x, T y) { x = min(x, y); }
template<typename T> void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 8005, M = 805;
ll f[N][M], g[N][M], sz[N];
vector<int> e[N];
int d[N];
int n, m;
int id[N], l[N], r[N], ts;
int dis[N];
struct BIT {
int a[N];
void upd(int q, int v) { for(int i = q; i < N; i += (i & -i)) a[i] += v; }
int qry(int q) { int ans = 0; for(int i = q; i; i -= (i & -i)) ans += a[i]; return ans; }
void upd(int ql, int qr, int v) { upd(ql, v); upd(qr + 1, -v); }
} t[M];
// int h[N][M];
void dfs(int x, int fa)
{
id[++ts] = x; l[x] = ts;
d[x] = d[fa] + 1;
sz[x] = 1; dis[x] = 1;
for(int i : e[x]) if(i != fa)
{
dfs(i, x);
sz[x] += sz[i];
chmax(dis[x], dis[i] + 1);
}
r[x] = ts;
static ll s[M];
memset(s, 0, sizeof s);
for(int i : e[x]) if(i != fa)
rep(k, 0, d[x])
s[k] += g[i][k];
rep(k, 0, d[x]) g[x][k] = k, f[x][k] = s[k] + k;
for(int i : e[x]) if(i != fa)
{
rep(k, 1, d[x]) chmax(f[x][k], k + s[k] - g[i][k] + f[i][k + 1]);
rep(k, 1, d[x])
{
// rep(j, l[i], r[i])
// h[id[j]][k] += s[k] - g[i][k];
t[k].upd(l[i], r[i], s[k] - g[i][k]);
}
}
rep(k, 1, d[x])
{
for(int i : e[x]) if(i != fa)
g[x][k] += g[i][k];
}
rep(o, l[x], r[x])
{
int i = id[o];
int k = d[i] - d[x];
// chmax(g[x][k], f[i][k + 1] + h[i][k] + k * k);
chmax(g[x][k], f[i][k + 1] + t[k].qry(o) + k * k);
}
}
void solve()
{
cin >> n >> m; m ++; ts = 0;
rep(i, 1, n) e[i].clear();
rep(i, 2, n)
{
int fa; cin >> fa;
e[fa].push_back(i);
}
memset(f, 0, sizeof f);
memset(g, 0, sizeof g);
// memset(h, 0, sizeof h);
memset(t, 0, sizeof t);
dfs(1, 0);
ll ans = f[1][1];
cout << ans << "\n";
}
signed main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
ios::sync_with_stdio(0);cin.tie(0);
int h; cin >> h;
while(h --) solve();
return 0;
}
D I.
#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;
template<typename T> inline void chmin(T& x, T y) { x = min(x, y); }
template<typename T> inline void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 5e4 + 5;
using ull = unsigned long long;
int n;
ll a[N];
ull ans[N];
ll suf[N], pre[N];
ll b[N], t[N], t2[N];
template<typename T, int N>
struct ST {
static const int K = __lg(N) + 1;
int n;
T st[K][N];
void init(int _n, T *a = NULL)
{
n = _n;
if(a != NULL) for(int i = 0; i <= n; i ++) st[0][i] = a[i];
for(int j = 1; j < K; j ++)
for(int i = 0; i <= n; i ++)
st[j][i] = min(st[j - 1][i], st[j - 1][min(n, i + (1 << j - 1))]);
}
T qry(int l, int r)
{
assert(l >= 0 && r <= n && l <= r);
int h = __lg(r - l + 1);
return min(st[h][l], st[h][r - (1 << h) + 1]);
}
} ;
ST<ll, N> sp, ss;
int l[N], r[N];
ll w[N];
struct dq {
pair<int, ll> a[N << 1], *l, *r;
void clear() { l = a + N, r = a + N - 1; }
void push_back(const pair<int, ll> &v) { *++r = v; }
void push_front(const pair<int, ll> &v) { *--l = v; }
void pop_back() { r --; }
void pop_front() { l ++; }
int back1() { return r->first; }
ll back2() { return r->second; }
int front1() { return l->first; }
ll front2() { return l->second; }
bool empty() { return l > r; }
} ;
void sol1(int l, int r)
{
rep(i, 1, n - l + 1) w[i] = suf[i] - ss.qry(i + l, min(n + 1, i + r));
static dq q;
q.clear();
rep(i, 1, n)
{
if(i <= n - l + 1)
{
while(!q.empty() && q.front2() < w[i]) q.pop_front();
q.push_front({i, w[i]});
}
while(!q.empty() && q.back1() + l <= i) q.pop_back();
chmax(b[i], q.back2());
}
}
void sol2(int l, int r)
{
int d = (r - l + 1) >> 1, u = r - d + 1;
rep(i, u, n) w[i] = pre[i] - sp.qry(max(0, i - r), i - u);
static dq q;
q.clear();
rep(i, 1, n)
{
int j = i + u - 1;
if(j <= n)
{
while(!q.empty() && q.front2() < w[j]) q.pop_front();
q.push_front({j, w[j]});
}
while(!q.empty() && q.back1() < i) q.pop_back();
chmax(b[i], q.back2());
}
}
void sol3(int l, int r)
{
int d = (r - l + 1) >> 1, u = r - d + 1;
rep(i, 1, n - u + 1) w[i] = suf[i] - ss.qry(i + u, min(n + 1, i + r));
static dq q;
q.clear();
rep(i, 1, n)
{
if(i <= n - u + 1)
{
while(!q.empty() && q.front2() < w[i]) q.pop_front();
q.push_front({i, w[i]});
}
while(!q.empty() && q.back1() + u <= i) q.pop_back();
chmax(b[i], q.back2());
}
}
void sol4(int l, int r)
{
int d = (r - l) >> 1;
rep(i, l, n)
{
ll L = sp.qry(max(0, i - l - d), i - l);
ll R = ss.qry(i + 1, min(n + 1, i + d + 1));
chmax(b[i], pre[n] - L - R);
}
}
void solve()
{
cin >> n; rep(i, 1, n) cin >> a[i];
rep(i, 1, n) pre[i] = pre[i - 1] + a[i];
per(i, n, 1) suf[i] = suf[i + 1] + a[i];
sp.init(n + 1, pre);
ss.init(n + 1, suf);
int q; cin >> q;
rep(i, 1, q) cin >> l[i] >> r[i];
a[0] = a[n + 1] = -1e18;
rep(i, 1, q)
{
memset(b, -0x3f, sizeof b);
sol1(l[i], r[i]);
if(l[i] != r[i])
{
sol2(l[i], r[i]);
sol3(l[i], r[i]);
sol4(l[i], r[i]);
}
ans[i] = 0;
rep(j, 1, n) ans[i] ^= b[j] * j;
}
rep(i, 1, q) cout << ans[i] << "\n";
}
signed main()
{
freopen("query.in", "r", stdin);
freopen("query.out", "w", stdout);
ios::sync_with_stdio(0);cin.tie(0);
int t = 1;
while(t --) solve();
return 0;
}
D II.
#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;
template<typename T> inline void chmin(T& x, T y) { x = min(x, y); }
template<typename T> inline void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 5e4 + 5;
using ull = unsigned long long;
int n;
ll a[N];
ull ans[N];
ll suf[N], pre[N];
ll b[N];
template<typename T, int N>
struct ST {
static const int K = __lg(N) + 1;
int n;
T st[K][N];
void init(int _n, T *a = NULL)
{
n = _n;
if(a != NULL) for(int i = 0; i <= n; i ++) st[0][i] = a[i];
for(int j = 1; j < K; j ++)
for(int i = 0; i <= n; i ++)
st[j][i] = max(st[j - 1][i], st[j - 1][min(n, i + (1 << j - 1))]);
}
T qry(int l, int r)
{
assert(l >= 0 && r <= n && l <= r);
int h = __lg(r - l + 1);
return max(st[h][l], st[h][r - (1 << h) + 1]);
}
} ;
ST<ll, N> sp, ss;
int l[N], r[N];
ll w[N];
struct dq {
pair<int, ll> a[N << 1], *l, *r;
void clear() { l = a + N, r = a + N - 1; }
void push_back(const pair<int, ll> &v) { *++r = v; }
void push_front(const pair<int, ll> &v) { *--l = v; }
void pop_back() { r --; }
void pop_front() { l ++; }
int back1() { return r->first; }
ll back2() { return r->second; }
int front1() { return l->first; }
ll front2() { return l->second; }
bool empty() { return l > r; }
} ;
int nxt[N];
ll t[N];
int ls[N], rs[N], rt;
void dfs(int x, ll w)
{
if(ls[x]) dfs(ls[x], w);
chmax(w, t[x]);
chmax(b[x], w);
if(rs[x]) dfs(rs[x], w);
}
vector<pair<int, ll>> upd[N];
void sol(int l, int r)
{
static dq q;
q.clear();
int lst = 0;
rep(i, 0, n) upd[i].clear();
rep(i, l, n)
{
int j = i - l;
while(!q.empty() && q.front2() > pre[j]) q.pop_front();
q.push_front({j, pre[j]});
while(q.back1() + r < i) q.pop_back();
upd[q.back1() + 1].push_back({i, pre[i] - q.back2()});
}
q.clear();
rep(i, 1, n)
{
for(auto [p, v] : upd[i])
{
while(!q.empty() && q.front2() < v) q.pop_front();
q.push_front({p, v});
}
while(q.back1() < i) q.pop_back();
chmax(b[i], q.back2());
}
memset(t, -0x3f, sizeof t);
rep(i, 1, n)
{
if(nxt[i] - i > r) continue;
int L = nxt[i] + l - 1, R = min(n, i + r - 1);
if(L > R) continue;
t[i] = sp.qry(L, R) - pre[i - 1];
}
dfs(rt, -1e18);
}
void solve()
{
cin >> n; rep(i, 1, n) cin >> a[i];
rep(i, 1, n) pre[i] = pre[i - 1] + a[i];
per(i, n, 1) suf[i] = suf[i + 1] + a[i];
sp.init(n + 1, pre);
ss.init(n + 1, suf);
int q; cin >> q;
rep(i, 1, q) cin >> l[i] >> r[i];
stack<int> s;
rep(i, 1, n)
{
int lst = 0;
while(s.size() && pre[i - 1] < pre[s.top() - 1]) nxt[lst = s.top()] = i, s.pop();
ls[i] = lst;
if(s.size()) rs[s.top()] = i;
else rt = i;
s.push(i);
}
while(s.size()) nxt[s.top()] = n + 1, s.pop();
a[0] = a[n + 1] = -1e18;
rep(i, 1, q)
{
memset(b, -0x3f, sizeof b);
sol(l[i], r[i]);
ans[i] = 0;
rep(j, 1, n) ans[i] ^= b[j] * j;
}
rep(i, 1, q) cout << ans[i] << "\n";
}
signed main()
{
freopen("query.in", "r", stdin);
freopen("query.out", "w", stdout);
ios::sync_with_stdio(0);cin.tie(0);
int t = 1;
while(t --) solve();
return 0;
}
D III.
#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;
template<typename T> inline void chmin(T& x, T y) { x = min(x, y); }
template<typename T> inline void chmax(T& x, T y) { x = max(x, y); }
typedef long long ll;
const int N = 5e4 + 5;
using ull = unsigned long long;
int n;
ll a[N];
ull ans[N];
ll suf[N], pre[N];
ll b[N], t[N], t2[N];
template<typename T, int N>
struct ST {
static const int K = __lg(N) + 1;
int n;
T st[K][N];
void init(int _n, T *a = NULL)
{
n = _n;
if(a != NULL) for(int i = 0; i <= n; i ++) st[0][i] = a[i];
for(int j = 1; j < K; j ++)
for(int i = 0; i <= n; i ++)
st[j][i] = min(st[j - 1][i], st[j - 1][min(n, i + (1 << j - 1))]);
}
T qry(int l, int r)
{
int h = __lg(r - l + 1);
return min(st[h][l], st[h][r - (1 << h) + 1]);
}
} ;
ST<ll, N> sp, ss;
void sol(int k, int vl, int vr)
{
k --;
if(vl > vr) return;
ll t = -1e18;
per(i, n, 1)
{
if(i & ((1 << k) - 1)) ;
else t = -1e18;
if(i >= vl) chmax(t, pre[i] - sp.qry(max(0, i - vr), i - vl));
chmax(b[i], t);
}
rep(i, 1, n)
{
if((i - 1) & ((1 << k) - 1)) ;
else t = -1e18;
if(i <= n - vl + 1) chmax(t, suf[i] - ss.qry(i + vl, min(n + 1, i + vr)));
chmax(b[i], t);
}
rep(o, 1, n >> k)
{
int L = (o << k) + 1, R = o + 1 << k;
int L2 = L - (1 << k), R2 = min(n, R + (1 << k));
ll mx = -1e18;
chmin(R2, L + vr - 1);
rep(i, R, R2) chmax(mx, pre[i] - sp.qry(max(L2 - 1, i - vr), min(L - 1, i - vl)));
rep(i, L, min(n, R)) chmax(b[i], mx);
}
}
int l[N], r[N];
const int K = 18;
ll w[K][N];
ll sw[K][K][N];
void solve()
{
cin >> n; rep(i, 1, n) cin >> a[i];
rep(i, 1, n) pre[i] = pre[i - 1] + a[i];
per(i, n, 1) suf[i] = suf[i + 1] + a[i];
sp.init(n + 1, pre);
ss.init(n + 1, suf);
int q; cin >> q;
rep(i, 1, q) cin >> l[i] >> r[i];
a[0] = a[n + 1] = -1e18;
memset(sw, -0x3f, sizeof sw);
rep(j, 1, n) sw[0][0][j] = w[0][j] = a[j];
rep(j, 1, n) sw[1][1][j] = w[1][j] = max(a[j] + a[j - 1], a[j] + a[j + 1]);
rep(i, 2, K - 1)
{
memset(b, -0x3f, sizeof b);
sol(i, i ? (1 << i - 1) + 1 : 1, 1 << i);
rep(j, 1, n) sw[i][i][j] = w[i][j] = b[j];
}
rep(i, 0, K - 1) rep(j, i + 1, K - 1) rep(k, 1, n)
sw[i][j][k] = max(sw[i][j - 1][k], w[j][k]);
rep(i, 1, q)
{
memset(b, -0x3f, sizeof b);
int pl = 0, pr = 0;
per(j, K - 1, 0) if((j ? (1 << j - 1) + 1 : 1) >= l[i]) pl = j;
rep(j, 0, K - 1) if((1 << j) <= r[i]) pr = j;
if(pl > pr + 1)
{
sol(pr + 1, l[i], r[i]);
}
else
{
rep(j, 1, n) b[j] = sw[pl][pr][j];
pl --, pr ++;
if(pl >= 0 && l[i] <= (1 << pl)) sol(pl, l[i], 1 << pl);
sol(pr, (1 << pr - 1) + 1, r[i]);
}
ans[i] = 0;
rep(j, 1, n) ans[i] ^= b[j] * j;
}
rep(i, 1, q) cout << ans[i] << "\n";
}
signed main()
{
freopen("query.in", "r", stdin);
freopen("query.out", "w", stdout);
ios::sync_with_stdio(0);cin.tie(0);
int t = 1;
while(t --) solve();
return 0;
}

浙公网安备 33010602011771号