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;
} 
posted @ 2026-08-21 16:50  lrj3247  阅读(5)  评论(2)    收藏  举报