[ABC396F] Rotated Inversions
题意
给出一个非负整数序列 \(A=(A_1,A_2,\cdots,A_n) \pod {0\le A_i\le m}\),对于 \(k=0,1,\cdots,m-1\),定义 \(B_i=(A_i+k)\bmod m\),求 \((B_1,B_2,\cdots,B_n)\) 的逆序对数。
思路
若忽视取模限制,因为每个数的相对大小关系不变,则逆序对数不变,因此我们对于每个 \(k\) 只需考虑在加上 \(k\) 后变为 \(0\) 的 \(B_i\) 对逆序对数产生的影响。
我们将 \(k=0,1,\cdots,m-1\) 看作 \(m-1\) 次操作,每次操作将 \(A\) 序列整体加 \(1\) 并对 \(m\) 取模。
考虑那些在操作前等于 \(m-1\) 的 \(A_i\)。因为 \(m-1\) 为 \(A\) 的最大值,所以这些数可以跟它们后面所有不等于 \(m-1\) 的 \(A_j\) 构成逆序对,同时不能跟前面任何一个 \(A_j\) 构成逆序对。
但是操作后这些 \(A_i\) 都变成了 \(0\),因为 \(0\) 为 \(A\) 的最小值,所以这些数可以跟前面所有不等于 \(0\) 的 \(A_j\) 构成逆序对,同时不能跟后面任何一个 \(A_j\) 构成了逆序对。
于是对于这些 \(A_i\),它们的操作会使得整个序列的逆序对数减去原来的贡献并加上现在的贡献。最初的逆序对数可以使用树状数组维护,操作产生的贡献可以动态维护,时间复杂度 \(O(n\log n)\),可以通过。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
vector<int> b[200005];
int n,m,a[200005],c[200005],ans;
void add(int x,int v){x++;while(x<=m+1) c[x]+=v,x+=(x&-x);
}
int qu(int x){x++;int res=0;while(x) res+=c[x],x-=(x&-x);return res;
}
signed main() {ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i],b[a[i]].push_back(i);for(int i=n;i>=1;i--)add(a[i],1),ans+=qu(a[i]-1);for(int i=m;i>=1;i--){for(int j=b[i].size()-1;j>=0;j--)ans-=n-b[i][j]-((int)(b[i].size())-1-j);for(int j=0;j<b[i].size();j++)ans+=b[i][j]-1-j;cout<<ans<<endl;}return 0;
}