LOJ167 康托展开 题解
康托展开:
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的名次,因此是可逆的。
X = A[0] * (n-1)! + A[1] * (n-2)! + … + A[n-1] * 0!
A[i] 指的是位于位置i后面的数小于A[i]值的个数,后面乘的就是后面还有多少个数的阶乘
这个算出来的数康拖展开值,是在所有排列次序 - 1的值,因此X+1即为在全排列中的次序
long long cantor()
{
long long ans=;
inc(,n,){
long long cnt=;
long long num=,sum=;
for(int j=i+;j<=n;j++){
if(a[j]<a[i]) ++cnt;
sum=sum*num%p;
++num;
}
ans=(ans+cnt*sum%p)%p;
}
return ans%p;
}
问:虽然知道了康托展开的方法,但怎样知道排名求排列呢?
答:那就使用逆康托展开!;
逆康托展开:
前面已经说到康拖展开是从序列到自然数的映射且是可逆的,那么逆康拖展开便是从自然数到序列的映射。
举例子:
在(1,2,3,4,5) 给出61可以算出起排列组合为34152
具体过程如下:
用 61 / 4! = 2余13,说明 ,说明比首位小的数有2个,所以首位为3。
用 13 / 3! = 2余1,说明 ,说明在第二位之后小于第二位的数有2个,所以第二位为4。
用 1 / 2! = 0余1,说明 ,说明在第三位之后没有小于第三位的数,所以第三位为1。
用 1 / 1! = 1余0,说明 ,说明在第二位之后小于第四位的数有1个,所以第四位为5。
static const int FAC[] = {, , , , , , , , , }; // 阶乘预处理
void decantor(int x, int n)
{
vector<int> v; // 存放当前可选数
vector<int> a; // 所求排列组合
for(int i=;i<=n;i++)
v.push_back(i);
for(int i=m;i>=;i--)
{
int r = x % FAC[i-];
int t = x / FAC[i-];
x = r;
sort(v.begin(),v.end());// 从小到大排序
a.push_back(v[t]); // 剩余数里第t+1个数为当前位
v.erase(v.begin()+t); // 移除选做当前位的数
}
}
但是......
你会发现,这样的时间复杂度是n^2的,我们无法接受这么暴力的算法;即使比枚举快乐很多;
那么,我们总不能整个ex康托展开,所以开始考虑优化;
从阶乘上入手?还是不够快。那么剩余优化的仅仅剩一个地方:统计小于a[i]个数.
这时我们会想到我们可爱的朋友:树状数组。
nlogn的复杂度,开心愉悦的AC掉了它;
#include <bits/stdc++.h>
#define p 998244353
#define inc(a,b,c) for(register int i=a;i<=b;i+=c)
using namespace std;
int n;
int a[1000010],c[1000010];
long long pre[1000010];
int lowbit(int x)
{
return x&(-x);
}
int query(int x)
{
int res=0;
while(x>0){
res+=c[x];
x-=lowbit(x);
}
return res;
}
void add(int x)
{
while(x<=n){
c[x]+=1;
x+=lowbit(x);
}
}
long long cantor()
{
long long ans=0;
for(register int i=n;i>=1;i--){
long long ask=query(a[i]);
add(a[i]);
long long tmp=pre[n-i];
ans=(ans+tmp*ask%p)%p;
}
return ans%p;
}
int main()
{
cin>>n;
pre[0]=1;
inc(1,n,1){
pre[i]=pre[i-1]*i%p;
}
inc(1,n,1){
scanf("%d",&a[i]);
}
cout<<cantor()+1; }
附:公式的证明
某一全排列序列的编号即等于排在它前面的全排列的个数,而由编号定义可知,其前面的全排列组成数都小于该全排列组成的数。
还是用例子来说明吧,更易于理解,考察3214,我们要求出比它小的全排列的个数,可以这样计算:
1. 千位取1或2,后三位由剩下的3个元素全排列,共2*3!种;
2. 千位取3,百位取小于2的元素,只能为1,后两位由剩下的2个元素全排列,共1*2!种;
3. 千位取3,百位取2,十位取小于1的元素,不存在;
4. 最后一项一定为0;
LOJ167 康托展开 题解的更多相关文章
- HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 题解报告:NYOJ 题目139 我排第几个(康托展开)
描述 现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=1 ...
- 题解报告:NYOJ 题目143 第几是谁?(逆康托展开)
描述 现在有"abcdefghijkl”12个字符,将其按字典序排列,如果给出任意一种排列,我们能说出这个排列在所有的排列中是第几小的.但是现在我们给出它是第几小,需要你求出它所代表的序列. ...
- 题解 P5367 【【模板】康托展开】
P5367 [模板]康托展开 感觉这题难度大概在绿题到蓝题之间qwq 一.洛谷日报[yummy]浅谈康托展开 如我想知道321是{1,2,3}中第几个小的数可以这样考虑 : 第一位是3,当第一位的数小 ...
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
- hdu 1430(BFS+康托展开+映射+输出路径)
魔板 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- 【BZOJ】3301: [USACO2011 Feb] Cow Line(康托展开)
http://www.lydsy.com/JudgeOnline/problem.php?id=3301 其实这一题很早就a过了,但是那时候看题解写完也是似懂非懂的.... 听zyf神犇说是康托展开, ...
- hdu3567 八数码2(康托展开+多次bfs+预处理)
Eight II Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 130000/65536 K (Java/Others)Total S ...
- HDU - 1430 魔板 【BFS + 康托展开 + 哈希】
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1430 思路 我刚开始 想到的 就是 康托展开 但是这个题目是 多组输入 即使用 康托展开 也是会T的 ...
随机推荐
- 任务Task、先后任务
Task类似后台线程. using System; using System.Threading; using System.Threading.Tasks;//引用命名空间 namespace Co ...
- 分布式-信息方式-ActiveMQ结合Spring
ActiveMQ结合 Spring开发■ Spring提供了对JMS的支持,需要添加 Spring支持jms的包,如下: <dependency> <groupId>org.a ...
- scrum例会报告+燃尽图01
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/9954 一.小组情况 组长:贺敬文组员:彭思雨 王志文 位军营 徐丽君队名 ...
- CentOS 7下载
CentOS 7官方下载地址:https://www.centos.org/download/ 转载https://blog.csdn.net/yxwmzouzou/article/details/7 ...
- Django admin 设置和定制
models 在 models.py 中定义,每个 model 是一个 class: from django.db import models class PerformanceData(models ...
- 全面解读php-运算符
一.运算符的优先级 二.短路作用 本文为袋鼠学习中的总结,如有转载请注明出处:https://www.cnblogs.com/chrdai/p/11074776.html
- 本地git 添加多个远程仓库
1.在本地找到,~/.ssh 文件夹 2.执行 ssh-keygen -t rsa -C "Winseek" -f "id-rsa-github" 3.生成了i ...
- django QueryDict 类型
如果没有值,返回默认值的写法 允许有多个同名的值,但是需要用getlist 访问. 如果用常规的访问只能访问到最后一个值.
- 安装mangodb
1.配置yum源 [root@www ~]# cat /etc/yum.repos.d/mongodb-org-3.4.repo [mongodb-org-3.4] name=MongoDB Repo ...
- angularjs的部分总结
就在这个星期,我们学习了一个神奇的框架叫:"Angular js",它的神奇之处不是它的功能有多强,甚至它的功能还是很简陋的,但是它的那种思想是非常牛逼的;他完全抛弃了我们现在所常 ...