[CF1539F]Strange Array
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1539F]Strange Array相关的知识,希望对你有一定的参考价值。
Strange Array
题解
考虑我们如何求出一个数与这个序列中间数之间的距离。
假设这个序列中有
x
x
x个数比
a
i
a_{i}
ai大,有
y
y
y个数与
a
i
a_{i}
ai一样,有
z
z
z个数比
a
i
a_{i}
ai小。
当
a
i
a_{i}
ai不小于这个序列的中间数时,它们之间的距离为
y
+
z
−
⌈
x
+
y
+
z
2
⌉
=
⌊
y
+
z
−
x
2
⌋
y+z-\\left\\lceil\\frac{x+y+z}{2}\\right\\rceil=\\left\\lfloor\\frac{y+z-x}{2}\\right\\rfloor
y+z−⌈2x+y+z⌉=⌊2y+z−x⌋。
当
a
i
a_{i}
ai不大于这个序列的中间数时,它们之间的距离为
x
+
y
−
⌊
x
+
y
+
z
2
⌋
=
⌈
x
+
y
−
z
2
⌉
x+y-\\left\\lfloor\\frac{x+y+z}{2}\\right\\rfloor=\\left\\lceil\\frac{x+y-z}{2}\\right\\rceil
x+y−⌊2x+y+z⌋=⌈2x+y−z⌉。
我们可以分大于中间数与小于中间数两种情况去求答案。
对于
a
i
a_{i}
ai不小于中间数的答案,我们先将所有数都赋值为
−
1
-1
−1,再从
i
=
1
i=1
i=1开始,将等于
i
i
i的数的值赋值为
1
1
1。
那么对于
a
j
=
i
a_{j}=i
aj=i,它的
y
+
z
−
x
y+z-x
y+z−x相当于是最大的一段区间和。
我们求最大的区间和可以利用线段树来维护每个位置的前缀,记点
i
i
i的前缀为
p
r
e
i
pre_{i}
prei,有
(
y
+
z
−
x
)
m
a
x
=
max
k
=
j
n
p
r
e
k
−
min
k
=
0
j
−
1
p
r
e
k
(y+z-x)_{max}=\\max_{k=j}^{n}pre_{k}-\\min_{k=0}^{j-1}pre_{k}
(y+z−x)max=k=jmaxnprek−k=0minj−1prek
我们可以通过线段树的区间修改来维护前缀,通过线段树的区间最值来求出它的最大/小前缀。
对于
a
i
a_{i}
ai不大于中间数的答案,做法是相同的,只需要从
i
=
n
i=n
i=n开始即可。
时间复杂度 O ( n l o g n ) O\\left(nlog\\,n\\right) O(nlogn)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int iv2=5e8+4;
const int lim=1000000;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,a[MAXN],ans[MAXN];
vector<int>vec[MAXN];
class SegmentTree{
public:
int trmx[MAXN<<2],trmn[MAXN<<2],lzy[MAXN<<2];
void pushup(int rt){
trmx[rt]=max(trmx[rt<<1],trmx[rt<<1|1]);
trmn[rt]=min(trmn[rt<<1],trmn[rt<<1|1]);
}
void pushdown(int rt,int l,int r){
if(lzy[rt]){
int mid=l+r>>1;
trmx[rt<<1]+=lzy[rt];trmx[rt<<1|1]+=lzy[rt];
trmn[rt<<1]+=lzy[rt];trmn[rt<<1|1]+=lzy[rt];
lzy[rt<<1]+=lzy[rt];lzy[rt<<1|1]+=lzy[rt];
lzy[rt]=0;
}
}
void build(int rt,int l,int r,int aw){
lzy[rt]=0;if(l==r){trmx[rt]=trmn[rt]=l*aw;return ;}int mid=l+r>>1;
build(rt<<1,l,mid,aw);build(rt<<1|1,mid+1,r,aw);pushup(rt);
}
void modify(int rt,int l,int r,int al,int ar,int aw){
if(l>r||l>ar||r<al||al>ar)return ;
if(al<=l&&r<=ar){trmx[rt]+=aw;trmn[rt]+=aw;lzy[rt]+=aw;return ;}
int mid=l+r>>1;pushdown(rt,l,r);
if(al<=mid)modify(rt<<1,l,mid,al,ar,aw);
if(ar>mid)modify(rt<<1|1,mid+1,r,al,ar,aw);
pushup(rt);
}
int queryMax(int rt,int l,int r,int al,int ar){
if(l>r||l>ar||r<al||al>ar)return -INF;int mid=l+r>>1,res=-INF;
if(al<=l&&r<=ar)return trmx[rt];pushdown(rt,l,r);
if(al<=mid)res=max(res,queryMax(rt<<1,l,mid,al,ar));
if(ar>mid)res=max(res,queryMax(rt<<1|1,mid+1,r,al,ar));
return res;
}
int queryMin(int rt,int l,int r,int al,int ar){
if(l>r||l>ar||r<al||al>ar)return INF;int mid=l+r>>1,res=INF;
if(al<=l&&r<=ar)return trmn[rt];pushdown(rt,l,r);
以上是关于[CF1539F]Strange Array的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces - 1539F Strange Array(线段树区间合并)
CF 873C Strange Game On Matrix(贪心)