CodeForces 501D – Misha and Permutations Summation(康托/逆康托展开+树状数组+二分)

该博客介绍了如何利用康托展开、树状数组和二分搜索解决CodeForces 501D问题,即求解两个排列组合的模n!和对应的排列。通过康托展开计算排列位置,使用树状数组优化统计过程,并通过模运算简化计算,最后用二分搜索实现逆康托展开。整个过程详细分析了算法的时间复杂度和实现步骤。
摘要由CSDN通过智能技术生成
题意:给两个排列,分别算出是第几小的排列,这两个数字求和以后再模n!得到一个数,输出这个数对应的排列。
思路:很明显的康托/逆康托展开。难点在于如何快速求解康托/逆康托以及模n!上。
在康托展开中,遍历每一位是在所难免的,时间复杂度是O(n),在统计比a[i]小的数字个数的时候显然不能遍历了,可以用树状数组加速,时间复杂度是O(lgn)。这里并不得到的数字加起来,因为可能达到n!,太大了,而是按i!,这样每一位的保存。这一步的总复杂度是O(nlgn)。
对a、b两个排列都进行康托展开,得到一个数组v,这是它们每一位i!的和。
这时候需要进行模n!。
数组v的组成是这样的v[n]*n!+v[n-1]*(n-1)!+…+v[1]*1!+v[0]*0!
可以发现如果v[0]大于1,那么它就可以进位给v[1]了,如果v[1]大于2那么它就可以进位给v[2]了。即v[i+1]+=v[i]/(i+1),v[i]=v[i]%(i+1)。这样就完成了模n!。
最后一步是逆康托展开。
显然数组v的每个数v[i]就是它模i!的商。所以问题就在于如何快速找到有k个比它小的数字的数是几。这一步使用二分解决。
#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值