P7828 [CCO 2021] Swap Swap Sort题解
P7828 [CCO 2021] Swap Swap Sort题解
把目标序列看成大小关系,题意便转换成了在给定大小关系,(认为\(c_1<c_2<c_3...\))的情况下,求每次交换相邻(\(c_b与c_{b+1}\))项关系后的逆序对数。
不难发现影响仅是交换值为\(c_b\)与\(c_{b+1}\)的逆序对数与顺序对数,即$\ans=ans-逆+顺\=ans-(cnt_{c_b} \times cnt_{c_{b+1}} - 顺)+顺\= ans+2顺-cnt_{c_b} \times cnt_{c_{b+1}} $。
问题转换成了求顺序对数,考虑根号分治,将所有\(a_i=x\)的数的下表放入一个vector,若两个数的出现次数都小于B,则直接在两个vector上暴力跑双指针即可,复杂度为\(O(B)\)。
若只要有一个出现次数不小于B,这样的数至多有$\left \lfloor \frac{n}{B} \right \rfloor \(个,直接预处理出他们和每个数字的顺序对数。若出现次数大于B的数是\)c_{b+1}\(而非\)c_b\(,需要求每个数字与他们的顺序对数,仅需用\)cnt_{c_b} \times cnt_{c_{b+1}} -顺\(即可,预处理复杂度为\)O(\frac{n^2}{B})$。
时间复杂度为\(O(\frac{n^2}{B}+qB)\),由基本不等式,当\(\frac{n^2}{B}=qB\)时有最小值,\(B=\frac{n}{\sqrt q}\)
然后你交上去发现MLE了,因为你预处理时需要存大于\(B\)的数对其他所有种类数的答案空间也是\(O(\frac{n^2}{B})\),即\(1e8\)个\(long long\),故应该将询问离线下来做,但是笔者太懒了,调整块长损失一定的时间使得空间合法反正很难跑满。
code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+15;
int rd(){
int w=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while('0'<=ch&&ch<='9') w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return w;
}
void wt(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) wt(x/10);
putchar(x%10+'0');
}
int n,k,q,a[N],c[N],mp[N],tot,ans[315][N],tr[N];
void add(int x,int val){
for(;x<=k;x+=(x&(-x))) tr[x]+=val;
return ;
}
int ask(int x){
int ret=0;
for(;x;x-=(x&(-x))) ret+=tr[x];
return ret;
}
vector <int> e[N];
int calc(vector <int> &x,vector <int> &y){
int ret = 0;
for(int i = 0 , j = 0 ; i<(int)x.size(); i++){
while(j<(int)y.size()&&y[j]<x[i]) ++j;
ret+=(int)y.size()-j;
}
return ret;
}
signed main(){
n=rd(),k=rd(),q=rd();int p = 300;
for(int i = 1 ; i<=n ; i++) e[a[i]=rd()].emplace_back(i);
for(int i = 1 ; i<=k ; i++) c[i] = i;
for(int i = 1 ; i<=k ; i++){
if((int)e[i].size()>=p){
mp[i]=++tot;
for(int j = 1 ; j<=k ; j++){
if(i==j) continue;
ans[mp[i]][j]=calc(e[i],e[j]);
}
}
}
int res = 0;
for(int i = 1 ; i<=n ; i++) res+=i-1-ask(a[i]),add(a[i],1);
while(q--){
int b=rd();
if(mp[c[b]])
res+=2*ans[mp[c[b]]][c[b+1]]-(int)e[c[b]].size()*(int)e[c[b+1]].size();
else if(mp[c[b+1]])
res+=(int)e[c[b]].size()*(int)e[c[b+1]].size()-2*ans[mp[c[b+1]]][c[b]];
else
res+=2*calc(e[c[b]],e[c[b+1]])-(int)e[c[b]].size()*(int)e[c[b+1]].size();
swap(c[b],c[b+1]);
wt(res),putchar('\n');
}
return 0;
}

浙公网安备 33010602011771号