[ 康托展开 树状数组 ] Codeforces504B Misha and Permutations Summation

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

利用康托展开可以在排列与变进制数间转化,其中变进制数就是从低到高第 ii 位的权值为 i! 的数。求答案时二分一下就好了。

#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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值