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;
}
}