F - Rotated Inversions

题目链接:https://atcoder.jp/contests/abc396/tasks/abc396_f

题意:

给定一个序列A,构造m个序列B,其中第i个序列第j个值为Bj= (Aj + i-1) %m

询问每个Bj的逆序对数目

思路:

由于模了m,所以一开始的序列每个元素的大小在[0,m-1)

发现当元素都+1时,对于序列中元素大小为m-1的:(m-1 +1)%m =0 ,而其他小于m-1的增加1,也就是相对顺序不变

于是只关注m-1元素的变化对 逆序对数目 的影响

对于这些元素:

  • 1 在它们之前的数,除了同类,其他数都比它们大,而变化前它们都比其他数大
  • 2 在它们之后的数,除了同类,其他数都比它们大,而变化前它们都比其他数大

因此左半边多构成了逆序对,右半边少构成了逆序对
将这些影响加起来获得每个询问的答案

记得开ll

int n,m;
int a[maxn],b[maxn];
int res;

void merge(int l,int r){
	if(l==r)return;
	int mid=l+r>>1;
	merge(l,mid);merge(mid+1,r);
	int i=l,j=mid+1,p=l;
	while(i<=mid&&j<=r){
		if(a[i]<=a[j]){
			b[p++]=a[i];i++;
		}else{
			b[p++]=a[j];j++;
			res+=mid+1-i;
		}
	}
	while(i<=mid){
		b[p++]=a[i++];
	}
	while(j<=r){
		b[p++]=a[j++];
	}
	for(int s=l;s<=r;s++){
		a[s]=b[s];
	}
}

vector<int> arr[maxn];
void solve(){
	cin>>n>>m;

	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i]%=m;
		arr[a[i]].pb(i);
	}
	merge(1,n);
	
	cout<<res<<endl;
	
	
	for(int k=1;k<=m-1;k++){
		for(int j=0;j<arr[m-k].size();j++){
			res+=arr[m-k][j]-1-j;
			
			res-=(n-arr[m-k][j]-(arr[m-k].size()-j-1));
		}
		cout<<res<<endl;
	}
}
posted @ 2025-03-12 19:20  Marinaco  阅读(35)  评论(0)    收藏  举报
//雪花飘落效果