【题解】CF2043C Sums on Segments
题意概要
一个数组,最多有一个数的绝对值不是
思路
这里提供一个 数据结构优化查询前缀和最值 的做法。
最多有一个数的绝对值不是
剩下的数要么是
因此,我们最后的值一定是至多
- 一个是由
(空区间) 扩展而来,并且扩展出的区间不包含 。 - 一个是由
扩展而来。
首先考虑第一种区间,我们求出不包含
这个很明显是一个区间最值问题,但是这里涉及到区间和,所以我们先把原数组
然后,我们把前缀和数组
对于
对于
对于此类区间得到的结果取个并集,就是此类区间最后的结果。
然后是第二种区间,由
此时这个区间一定包含
向左扩展变化的最小值加上向右扩展变化的最小值,就是此类区间的最小区间和。
向左扩展变化的最大值加上向右扩展变化的最大值,就是此类区间的最大区间和。
最后对两种区间求得的结果再取一个并集即可。
时间复杂度:
AC CODE
// Problem: C. Sums on Segments
// Contest: Codeforces - Educational Codeforces Round 173 (Rated for Div. 2)
// URL: https://codeforces.com/contest/2043/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define int long long
#define inf 2e18
#define ull unsigned long long
#define ls o << 1
#define rs o << 1 | 1
using namespace std;
const int N = 2e5 + 9;
int a[N];
int tmx[N << 2], tmi[N << 2];
int n;
//线段树维护区间最值
void pushup(int o)
{
tmx[o] = max(tmx[ls], tmx[rs]);
tmi[o] = min(tmi[ls], tmi[rs]);
}
void build(int s = 1, int e = n, int o = 1)
{
if(s == e)return tmx[o] = a[s], tmi[o] = a[s], void();
int mid = s + e >> 1;
build(s, mid, ls);
build(mid + 1, e, rs);
pushup(o);
}
int querymx(int l, int r, int s = 1, int e = n, int o = 1)
{
if(l <= s && e <= r) {
return tmx[o];
}
int mid = s + e >> 1;
int res = -inf;
if(mid >= l)res = max(res, querymx(l, r, s, mid, ls));
if(mid + 1 <= r)res = max(res, querymx(l, r, mid + 1, e, rs));
return res;
}
int querymi(int l, int r, int s = 1, int e = n, int o = 1)
{
if(l <= s && e <= r) {
return tmi[o];
}
int mid = s + e >> 1;
int res = inf;
if(mid >= l)res = min(res, querymi(l, r, s, mid, ls));
if(mid + 1 <= r)res = min(res, querymi(l, r, mid + 1, e, rs));
return res;
}
void solve()
{
cin >> n;
for(int i = 1;i <= n;i ++)cin >> a[i];
int ix = -1;
for(int i = 1;i <= n;i ++)
if(abs(a[i]) != 1)ix = i;
for(int i = 1;i <= n;i ++)//前缀和
a[i] += a[i - 1];
build();//构建线段树
if(ix == -1)ix = n + 1;
int nomi = 0, nomx = 0;
//第一类区间
for(int i = 1;i <= n;i ++) {
if(i == ix)continue;
if(i <= ix) {
nomi = min(nomi, querymi(i, ix - 1) - a[i - 1]);
nomx = max(nomx, querymx(i, ix - 1) - a[i - 1]);
} else {
nomi = min(nomi, querymi(i, n) - a[i - 1]);
nomx = max(nomx, querymx(i, n) - a[i - 1]);
}
}
//第二类区间
int hasmi = 0, hasmx = 0;
if(ix <= n) {
hasmi = a[ix] - a[ix - 1];
hasmx = a[ix] - a[ix - 1];
int lmi = 0, lmx = 0;
int rmi = 0, rmx = 0;
int now = 0;
for(int i = ix - 1;i;i --) {
now += a[i] - a[i - 1];
lmi = min(lmi, now);
lmx = max(lmx, now);
}
now = 0;
for(int i = ix + 1;i <= n;i ++) {
now += a[i] - a[i - 1];
rmi = min(rmi, now);
rmx = max(rmx, now);
}
hasmi = hasmi + lmi + rmi;
hasmx = hasmx + lmx + rmx;
}
set<int> ans;
for(int i = nomi;i <= nomx;i ++)ans.insert(i);
for(int i = hasmi;i <= hasmx;i ++)ans.insert(i);
cout << ans.size() << '\n';
for(auto &i : ans)cout << i << ' ';
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t = 1;cin >> t;
while(t --)solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库