利用康托展开可以在排列与变进制数间转化,其中变进制数就是从低到高第 ii 位的权值为 的数。求答案时二分一下就好了。
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,m,x,k;
int a[N];
int c[N];
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=j&-j) ++c[j];
for(int i=1;i<=n;i++) {
scanf("%d",&x);
for(int j=x;j;j-=j&-j) a[i]+=c[j];
for(int j=x+1;j<=n;j+=j&-j) --c[j];
}
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=j&-j) ++c[j];
for(int i=1;i<=n;i++) {
scanf("%d",&x);
for(int j=x;j;j-=j&-j) a[i]+=c[j];
for(int j=x+1;j<=n;j+=j&-j) --c[j];
}
for(int i=n;i;i--)
a[i-1]+=a[i]/(n-i+1),a[i]%=n-i+1;
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=j&-j) ++c[j];
for(int i=1;i<=n;i++) {
int l=1,r=n;
while(l<=r) {
int Mid=l+r>>1,s=0;
for(int j=Mid-1;j;j-=j&-j) s+=c[j];
if(s<=a[i]) l=Mid+1;else r=Mid-1;
}
for(int j=r;j<=n;j+=j&-j) --c[j];
printf("%d ",r-1);
}
return 0;
}

本文介绍了一种利用康托展开实现排列与变进制数相互转换的方法,并通过具体算法实现进行了解释说明。该算法使用了二分查找来提高效率。
668

被折叠的 条评论
为什么被折叠?



