当前位置: 首页 > news >正文

2026 ICPC Asia Pacific Championship - E. Parallel Sums

题目连接

You are given two integers \(n\) and \(m\). For a sequence of \(n\) integers \(A=(a_1, a_2, \ldots, a_n)\), the parallel sums of \(A\) are the \(n-m+1\) integers \(s_1, s_2, \ldots, s_{n-m+1}\) defined by \(s_i = a_i + a_{i+1} + \ldots + a_{i+m-1}\) for each \(i\) (\(1 \leq i \leq n-m+1\)).

You are given the values of \(s_1, s_2, \ldots, s_{n-m+1}\). Your task is to answer \(q\) queries, described as follows. In the \(j\)-th query, you are given two integers \(l_j\) and \(r_j\), and you are asked to find the smallest possible value of \(\max(a_{l_j}, a_{l_j+1}, \ldots, a_{r_j})\) among all sequences \(A=(a_1, a_2, \ldots, a_n)\) of \(n\) integers (possibly negative) such that \(s_1, s_2, \ldots, s_{n-m+1}\) are the parallel sums of \(A\). Or determine if this value can be arbitrarily small.


观察到,\(a_{m + i} - a_i = s_{i + 1} - s_i\),这告诉我们可以按照模 \(m\) 对所有的数字进行分类,重写方程组可以得到:

\[\begin{cases} a_{m + 1} - a_1 = s_2 - s_1 \\ \cdots \\ a_{n} - a_{n - m} = s_{n - m + 1} - s_{n - m} \\ \sum\limits_{i = 1}^{m} a_i = s_1 \end{cases} \]

对模 \(m\)\(d\) 的所有 \(\{a\}\),我们重写为 \(b_{1}, \, \cdots, \, b_{k}\),容易得知他们的差分是确定的,这启示我们如果想要找到一段区间的最小 \(\max\),可以通过平衡分配 \(a_1, \, \cdots, \, a_m\) 来是的区间中最大的 \(b_i\) 最小,因此,任何长度小于 \(m\) 的区间都可以使得最大值无限小,反之,必定取遍 \(s_1\) 所覆盖的所有数字,我们不妨设 \(c_d\) 表示余数为 \(d\) 的元素在 \([l, \, r]\) 区间中的最大值与组成 \(s_1\)\(a_d\) 的差,显然最大的元素可以取 \(\left\lceil\dfrac{s_1 + \sum_{i = 1}^{m}c_i}{m}\right\rceil\),所以,我们的目标是求出最大的 \(c_i\)

  • \(m \le \sqrt{n}\) 时,我们可以对每个余数类建立一个 ST 表,将 \([l, \, r]\) 的区间映射到每个余数类内取最大值。

  • \(m > \sqrt{n}\) 时,每个余数类里的元素个数较少,因此我们可以求出覆盖第 \(i\) 到第 \(j\) 个元素,前 \(m\) 个余数类的前缀和,询问一个区间 \([l, \, r]\) 时,将这个区间分为 \(3\) 个块,如下:
    image
    于是我们可以在 \(O(1)\) 的复杂度处理每个询问。

总时间复杂度 \(O((n + q)\sqrt{n})\)

参考代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define i128 __int128
#define ld long double
#define pb push_back
#define PII pair<ll, ll>
#define PPI pair<ll, PII>
#define clr(f, n) memset(f, 0, sizeof(int) * (n))
#define cpy(f, g, n) memcpy(f, g, sizeof(int) * (n))
#define rev(f, n) reverse(f, f + (n))
const int N = 2e5 + 10, mod = 998244353, INF = 1e9;
const int B = 450;int n, m, q;
int lg2[N], len[N];
ll s[N], a[N], b[N];
vector<int> pos[N];
vector<vector<ll>> st[B], maxx[N];void build1() {lg2[0] = -1;for (int i = 1; i <= n; i ++ ) lg2[i] = lg2[i >> 1] + 1;for (int d = 1; d <= m; d ++ ) {for (int i = d; i <= n; i += m) pos[d].push_back(i);len[d] = pos[d].size();st[d].resize(lg2[len[d]] + 1, vector<ll>(len[d] + 1));for (int i = 0; i <= lg2[len[d]]; i ++ ) {for (int j = 1; j + (1 << i) - 1 <= len[d]; j ++ ) {if (!i) st[d][i][j] = b[pos[d][j - 1]];else st[d][i][j] = max(st[d][i - 1][j], st[d][i - 1][j + (1 << i - 1)]);}}}
}// x-th element is in d-group's y-th element
// x = d + y * m -> y = (x - d) / m
// L = ceil((x - d) / m), R = floor((x - d) / m)
ll query1(int d, int l, int r) {int L = (l - d + m - 1) / m + 1;int R = (r - d) / m + 1;int t = lg2[R - L + 1];return max(st[d][t][L], st[d][t][R - (1 << t) + 1]);
}void build2() {for (int d = 1; d <= m; d ++ ) {for (int i = d; i <= n; i += m) pos[d].push_back(i);len[d] = pos[d].size();maxx[d].resize(len[1] + 2, vector<ll>(len[1] + 2));for (int i = 1; i <= len[d]; i ++ ) {for (int j = i; j <= len[d]; j ++ ) {if (i == j) maxx[d][i][i] = b[pos[d][i - 1]];else maxx[d][i][j] = max(maxx[d][i][j - 1], b[pos[d][j - 1]]);}}}maxx[0].resize(len[1] + 2, vector<ll>(len[1] + 2));for (int d = 1; d <= m; d ++ ) {for (int i = 1; i <= len[d]; i ++ ) {for (int j = i; j <= len[d]; j ++ ) {maxx[d][i][j] += maxx[d - 1][i][j];}}}
}ll query2(int l, int r) {int fir = (l - 1) % m + 1, sec = (r - 1) % m + 1;int p = (l - 1) / m + 1, q = (r - 1) / m + 1;ll res = 0;res += maxx[min(fir - 1, sec)][p + 1][q];if (fir <= sec) res += maxx[sec][p][q] - maxx[fir - 1][p][q];else res += maxx[fir - 1][p + 1][q - 1] - maxx[sec][p + 1][q - 1];res += maxx[m][p][q - 1] - maxx[max(fir - 1, sec)][p][q - 1];return res;
}void solve() {cin >> n >> m;for (int i = 1; i <= n - m + 1; i ++ ) cin >> s[i];for (int i = 1; i <= n - m + 1; i ++ ) a[i] = s[i] - s[i - 1];for (int i = m; i <= n; i ++ ) b[i] = b[i - m] + a[i - m + 1];cin >> q;if (m < B) {build1();while (q -- ) {int l, r;cin >> l >> r;if (r - l + 1 < m) cout << "unbounded\n";else {ll sum = 0;for (int i = 1; i <= m; i ++ ) sum += query1(i, l, r);if (sum < 0) sum = sum / m;else sum = (sum + m - 1) / m;cout << sum << "\n";}}} else {build2();while (q -- ) {int l, r;cin >> l >> r;if (r - l + 1 < m) cout << "unbounded\n";else {ll sum = query2(l, r);if (sum < 0) sum = sum / m;else sum = (sum + m - 1) / m;cout << sum << "\n";}}}
}int main() {ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int T = 1;// cin >> T;while (T -- ) solve();return 0;
}
http://www.jsqmd.com/news/603507/

相关文章:

  • [Windows] EchoTrace v3.1.0 W信聊天记录导出、分析与年度报告生成工具
  • 拒绝盲目跟风!2026高口碑主治医师机构红榜揭秘,看完再选不踩雷 - 医考机构品牌测评专家
  • JBoltAI框架4.2版本更新:Java开发者的AI新利器
  • 从‘听不清’到‘听得准’:深入FunASR的VAD模型,教你调参优化语音识别在嘈杂环境下的表现
  • 保姆级教程:从开启到分析,手把手用Jcmd和NMT给你的SpringBoot应用做一次“内存体检”
  • 数据集|番茄叶子病虫害分类数据集11类
  • Windows 11系统优化深度解析:Win11Debloat技术架构与实战指南
  • LIF蛋白在胰腺癌旁分泌信号中的作用机制与临床意义
  • 告别虚拟机!在Win10上为ARM开发板(如TI AM62x)搭建Qt Widgets开发环境全记录
  • MTR中的Motion Query Pair:如何提升多模态轨迹预测的精度?
  • Python3与OpenSSL版本依赖详解:为什么你的CentOS总是报No module named ‘_ssl‘?
  • 效率翻倍:用快马AI生成winclaw高效开发模板与健壮性组件
  • 定义“验收标准”:如何与验证团队制定软件的“金标准”
  • LC滤波器选型避坑指南:为什么你的高频噪声总是滤不干净?
  • Qt信号与槽连接实战:从`private slots`访问权限到新版连接语法的避坑指南
  • 笔记本散热优化:G-Helper风扇智能控制工具解决设计师的散热难题
  • 告别Windows卡顿困扰:Win11Debloat开源工具带来的系统性能变革
  • python python-dotenv
  • 华为FusionCompute虚拟机热升级实战:CPU、内存、磁盘在线扩容技巧
  • 从LoadRunner到Jmeter:性能测试工具实战对比(含面试加分项整理)
  • 【Netty】【调试工具】----Windows上网络调试助手NetAssist的使用(Java 开发者实用指南)
  • Python全栈入门到实战【进阶篇 7】面向对象实战:小型学生管理系统V2.0(整合所有知识点)
  • 嵌入式PWM输入解析库:基于GPIO中断的轻量级实现
  • JBoltAI Agent OS:企业AI转型的“智慧管家”
  • 从原理到代码:手把手教你用Matlab实现Tsai手眼标定(避坑指南)
  • Linux内核中的设备驱动开发详解
  • 龙芯k - 久久派开发环境搭建及内核升级(上)
  • HarmonyOS应用集成华为Account Kit登录功能全流程解析
  • python environs
  • 企业AI Agent的“交通管理局”