首页 > 其他分享 >CF2043C 题解

CF2043C 题解

时间:2024-12-25 12:08:27浏览次数:7  
标签:int 题解 sum pos mx 值域 CF2043C upd

CF2043C 题解

题意

给定一个除了 \(-1,1\) 之外,最多存在一个 \(x,x\in[-10^9,10^9]\) 的数的序列,求其子段和的所有可能值,从小到大输出。

分析

很容易就去思考如何从这个特殊的 \(x\) 入手。于是先排除这个特例,考虑全都是 \(1,-1\) 的情形,那么顺序从左到右不断加入 \(a_i\) ,可以发现可以通过维护当前值域的上下界来解决问题。最后我们对于 \(x\) 之前的数统计一遍, \(x\) 之后的数倒序统计一遍,然后通过 \(x\) 把两边合并起来就好了。

赛时就是这么想的,思路也大体正确了。

但是存在的一个问题是,值域中的某些数,可能并不能和当前这个 \(a_i\) 拼接到一起,因为它可能不是以 \(a_{i-1}\) 结尾的。比赛的时候是这么写的,很麻烦,最后也没有调出来。

值域统计

不妨换一个角度思考,一个 \([l,r]\) 的子段和可以表示为 \(sum_r-sum_{l-1}\),由于 \(x\) 比较特殊,我们还是像上文提到的那样对于 \(x\) 的两边分别统计,最后单独考虑 \(x\)。

这样对于一个固定的 \(i\) 来说,\(sum_i-sum_j\) 的取值一定是在整数意义下连续的。因为任意的 \(sum_i\) 和 \(sum_{i-1}\) 相比,绝对值只会相差 \(1\) ,这就是 \(1,-1\) 的带来的特殊性。(这段比较抽象,建议画一个 \(s_i\) 的散点图来理解)

所以只需要考虑前缀和的前缀 \(max\) 和 \(min\) 就可以了,对于一个 \(s_i\),\([s_i-pmax,s_i-pmin]\) 之间的所有整数一定都是可以取到的,这样我们就成功计算出了以 \(a_i\) 为结尾的子段值域。

注意,这仅仅是以 \(a_i\) 为结尾的值域情况,我们不断维护它,是为了到最后能和 \(x\) 拼接起来,但是如果直接把它当成答案,肯定会有所遗漏,因为答案子段的结尾并不仅仅只是一个固定的元素,因此,对于所有算出来的值域,我们要取并集。

至于这个取并集过程的实现,观察到相邻两个元素的值域相差不会太大,我们只需要把每次更新值域后 被遗漏的部分提前标记为 true 就可以了。当然,在差分数组上操作,最后前缀和一遍的 trick 也是可以的。

以上是对于 \(x\) 左侧的计算方法,对于 \(x\) 的右侧来说,倒序枚举如法炮制即可。

对 \(x\) 两侧的值域进行合并

记 \(x\) 对应的下标为 \(pos\)。

假设左边以 \(a_{pos-1}\) 为结尾的值域是 \([l,r]\),右边以 \(a_{pos+1}\) 为结尾的值域是 \([L,R]\)。

很明显的是,最后能够取到的就是 \([x,x]\cup[l+x,r+x]\cup[L+x,R+x]\cup[l+L+x,r+R+x]\),把这一部分并进答案即可。

我个人的实现方法过于抽象,不过最后还是过了就行。

记得要单独把 \(0\) 也标记为 true。

Code

#include<bits/stdc++.h>
using namespace std;
int T,n;
const int N=2e5+10;
int a[N];
set<int> les,mor;
vector<int> output;
inline void out(set<int> &s){for(int x:s)cout<<x<<' ';}
inline void solve()
{
    cin>>n;
    les.clear(),mor.clear(),output.clear();
    vector<int> vis(2*n+10,0);
    auto upd=[&](int l,int r)
    {
        for(int i=l;i<=r;++i)
        {
            if(i<-n)les.insert(i);
            else if(i>n)mor.insert(i);
            else vis[i+n]=1;
        }
    };
    for(int i=1;i<=n;++i)cin>>a[i];
    int pos=n+1>>1;//随便钦定一个位置即可
    for(int i=1;i<=n;++i)if(a[i]!=1&&a[i]!=-1){pos=i;break;}
    int l=0,r=0,s=0;
    int mx=0,mn=0;
    for(int i=1,nowl,nowr;i<pos;++i)
    {
        s+=a[i];
        nowl=s-mx,nowr=s-mn;
        for(int j=l;j<nowl;++j)vis[j+n]=1;
        for(int j=r;j>nowr;--j)vis[j+n]=1;
        mx=max(mx,s),mn=min(mn,s);
        l=nowl,r=nowr;
    }
    int L=0,R=0;
    s=0,mx=0,mn=0;
    for(int i=n,nowl,nowr;i>pos;--i)
    {
        s+=a[i];
        nowl=s-mx,nowr=s-mn;
        for(int j=L;j<nowl;++j)vis[j+n]=1;
        for(int j=R;j>nowr;--j)vis[j+n]=1;
        mx=max(mx,s),mn=min(mn,s);
        L=nowl,R=nowr;
    }
    int x=a[pos];
    upd(l,r);
    upd(L,R);
    upd(x,x);
    upd(l+x,r+x);
    upd(L+x,R+x);
    upd(l+L+x,r+R+x);
    vis[n]=1;
    for(int i=-n;i<=n;++i)if(vis[i+n])output.push_back(i);
    cout<<les.size()+output.size()+mor.size()<<'\n';
    out(les);
    for(int val:output)cout<<val<<' ';
    out(mor);
    cout<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--)solve();
    return 0;
}

标签:int,题解,sum,pos,mx,值域,CF2043C,upd
From: https://www.cnblogs.com/Hanggoash/p/18630101

相关文章

  • P6779 [Ynoi2009] rla1rmdq 题解
    Description给定一棵\(n\)个节点的树,树有边权,与一个长为\(n\)的序列\(a\)。定义节点\(x\)的父亲为\(fa(x)\),根\(rt\)满足\(fa(rt)=rt\)。定义节点\(x\)的深度\(dep(x)\)为其到根简单路径上所有边权和。有\(m\)次操作:1lr:对于\(l\lei\ler\),\(a_i\lef......
  • 【Web】2024“国城杯”网络安全挑战大赛决赛题解(全)
    最近在忙联通的安全准入测试,很少有时间看CTF了,今晚抽点时间回顾下上周线下的题(期末还没开始复习......
  • 题解 P9885【[Qingdao18A] Sequence and Sequence】
    具体数学还在发力!题目描述考虑下列两个序列\(P\)和\(Q\)。我们用\(P(i)\)表示序列\(P\)中的第\(i\)个元素,用\(Q(i)\)表示序列\(Q\)中的第\(i\)个元素:序列\(P\)是一个已排序的序列,其中,对于所有\(k\in\mathbb{Z^+}\),\(k\)在序列\(P\)中出现\((k+1)\)......
  • [THUSC2015] 异或运算 题解
    学到新思路了:求解\(k\)大值时,可以将所有元素放一块一起跑。考虑到\(n,q\)奇小无匹,我们便可以制造一个\(O(qn\logV)\)的代码。那么对于我们不想在时间复杂度中出现的\(m\),我们直接把他扔进可持久化\(Trie\)中销赃。再根据刚才那个思路,将\([u,d]\)中所有点扔进可持......
  • ZJOI2016 旅行者 题解
    ZJOI2016旅行者题解题目大意:给定一个\(n\timesm\)的网格图,相邻的四连通的点之间有给定边权的双向边,有\(Q\)个离线询问,问两个点之间的最短路。\(n\timesm\le2\times10^4,Q\le10^5\)。发现了吗?和上次省选组的三角剖分那道题很像,这种平面图上的最短路很有可能是分治......
  • 省选模拟题解
    \(T1\)题解题意:有一张\(n\)个点的有标号无向图,分为了\(k\)个连通块,第\(i\)个连通块的大小是\(s_i\),每个连通块都是完全图(节点之间两两有边)。要加\(k-1\)条边使得图连通,计算所有连边方案的权值和。假设第\(i\)个连通块被多加了\(d_i\)条边,那么该连边方案的权值为\(......
  • 湖南科技大学2024年计算机程序设计新生赛题解
    @目录前言前置知识补充问题A:珂朵莉解题思路代码问题B:可莉的烦恼解题思路代码问题C:小A的画解题思路代码问题D:KMP自动机fail树dfs序建可持久化线段树解题思路代码问题E:谜题:结局解题思路代码问题F:奶龙列阵(easyversion)解题思路代码问题G:小A的密码解题思路代码问......
  • [BZOJ2741][FOTILE模拟赛] L 题解
    相当好的题目,虽然和我前几天出的题重了qwq。\(lmx\)是我们的红太阳,没有他我们就会死!!!暴力枚举一个端点,然后用可持久化\(01\Trie\)或者离线\(Trie\)(当然这题用不了,但不强制在线的话是可以的)得到答案。时间复杂度\(O(nm\logn)\),过不了,考虑优化。红太阳\(lmx\)曾经说过:当......
  • umount: /xxx: target is busy问题解决
    在卸载文件系统的时候,提示umount:/tqls_system:targetisbusy,表示挂载的文件系统正在被使用。要卸载文件系统,必须结束使用文件或者目录的进程`fuser`命令用于查看使用特定文件或者文件系统的进程ID主要参数如下:```-mNAME,--mountNAME NAMEspecifiesafileonamou......
  • USACO24DEC Cake Game S 题解 [ 黄 ] [ 前缀和 ] [ adhoc ]
    CakeGame:小清新前缀和题,但是我场上想了半天优先队列贪心假完了/ll/ll/ll。观察本题有三个重要的结论,我们依次进行观察。不难发现,第二个牛一定会拿\(\frac{n}{2}-1\)个蛋糕走。同时它拿走的蛋糕一定是左边一段、右边一段。如果它要使自己的分数最大化,那么显然就是要将左边和......