CodeForces 1558F Strange Sort
首先我们考虑将原问题缩小值域,即将原序列变为 \(01\) 序列。那么现在问题变成了在 \(01\) 序列上怎么做,以及怎么转化成 \(01\) 序列。
首先我们设定一个阈值 \(k\),令所有小于 \(k\) 的数变为 \(0\),其它数变为 \(1\)。对于所有的 \(k\) 求出的最大交换次数即为原问题的答案。
考虑如果我们有一个固定的 \(01\) 序列,应该怎么求解,显然我们可以 dp。
首先我们假设序列中有 \(m\) 个 \(0\)。那么我们还可以注意到,后面的 \(0\) 一定比前面的更晚归位。
于是我们设 \(f_i\) 表示第 \(i\) 个 \(0\) 归位需要几步。显然有 \(f_i\leftarrow \max(f_{i-1}+1,(k_i+(p_i\bmod 2)))\)。
于是有 \(f_m\leftarrow \displaystyle\max_{i=t}^{m}(k_i+(p_i\bmod 2)+m-i)\)。
我们现在相当于要动态把一个序列中的 \(1\) 改为 \(0\),然后维护上面的式子,直接是用线段树即可。
#include<bits/stdc++.h>
#define int long long
#define N 200005
#define pii pair<int,int>
#define x first
#define y second
#define pct __builtin_popcount
#define mod 998244353
using namespace std;
int T=1,n,a[N],p[N],inf=2e9;
struct sgt{
int tr[N<<2],s[N<<2],s1[N<<2],lzy[N<<2];
void pushup(int u){
tr[u]=max(tr[u<<1],tr[u<<1|1]);
s[u]=s[u<<1]+s[u<<1|1];
s1[u]=s1[u<<1]+s1[u<<1|1];
}
void build(int u,int l,int r){
lzy[u]=0;
if(l==r){
tr[u]=0;
s[u]=1;
s1[u]=1;
return;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void maketag(int u,int v){
tr[u]+=v;
lzy[u]+=v;
}
void pushdown(int u){
maketag(u<<1,lzy[u]);
maketag(u<<1|1,lzy[u]);
lzy[u]=0;
}
void modify1(int u,int l,int r,int L,int R,int v){
if(L>R)return;
if(l>=L&&r<=R){
maketag(u,v);
return;
}
int mid=l+r>>1;
pushdown(u);
if(L<=mid)modify1(u<<1,l,mid,L,R,v);
if(R>mid)modify1(u<<1|1,mid+1,r,L,R,v);
pushup(u);
}
void modify(int u,int l,int r,int p){
if(l==r){
tr[u]=0;
s1[u]--;
return;
}
int mid=l+r>>1;
pushdown(u);
if(p<=mid)modify(u<<1,l,mid,p);
else modify(u<<1|1,mid+1,r,p);
pushup(u);
}
int qryp(int u,int l,int r){
if(l==r&&s1[u]==0)return n+1;
if(l==r)return l;
int mid=l+r>>1;
pushdown(u);
if(s1[u<<1]!=0)return qryp(u<<1,l,mid);
else return qryp(u<<1|1,mid+1,r);
}
int qry1(int u,int l,int r,int L,int R){
if(L>R)return 0;
if(l>=L&&r<=R)return s1[u];
int mid=l+r>>1;
int res=0;
pushdown(u);
if(L<=mid)res+=qry1(u<<1,l,mid,L,R);
if(R>mid)res+=qry1(u<<1|1,mid+1,r,L,R);
return res;
}
int qry(int u,int l,int r,int L,int R){
if(L>R)return 0;
if(l>=L&&r<=R)return tr[u];
int mid=l+r>>1;
int res=0;
pushdown(u);
if(L<=mid)res=max(res,qry(u<<1,l,mid,L,R));
if(R>mid)res=max(res,qry(u<<1|1,mid+1,r,L,R));
return res;
}
}s;
void solve(int cs){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
p[a[i]]=i;
}
s.build(1,1,n);
int res=0;
for(int k=1;k<=n;k++){
int i=p[k];
s.modify(1,1,n,i);
s.modify1(1,1,n,1,i-1,1);
s.modify1(1,1,n,i+1,n,-1);
s.modify1(1,1,n,i,i,s.qry1(1,1,n,1,i-1)+(i%2)+(n-s.qry1(1,1,n,1,n)-i+s.qry1(1,1,n,1,i)));
int pos=s.qryp(1,1,n);
res=max(res,s.qry(1,1,n,pos,n));
}
cout<<res<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
// init();
for(int cs=1;cs<=T;cs++){
solve(cs);
}
return 0;
}