康托展开&逆展开算法笔记
康托展开(有关全排列)
康托展开:已知一个排列,求这个排列在全排列中是第几个
康托展开逆运算:已知在全排列中排第几,求这个排列
定义:
X=an(n-1)!+an-1(n-2)!+...+ai(i-1)!+...+a21!+a1*0!
ai为整数,并且0<=ai<i(1<=i<=n)
简单点说就是,判断这个数在其各个数字全排列中从小到大排第几位。
比如 1 3 2,在1、2、3的全排列中排第2位。
康托展开有啥用呢?
维基:n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出对应的全排列。
它可以应用于哈希表中空间压缩,而且在搜索某些类型题时,将VIS数组量压缩。比如:八数码,魔板等题
康托展开的大小即为在此排列前存在的排列的个数
比如 2 1 4 3 这个数,求其展开:
从头判断,至尾结束,
① 比 2(第一位数)小的数有多少个->1个 就是1,1*3!
② 比 1(第二位数)小的数有多少个->0个 0*2!
③ 比 4(第三位数)小的数有多少个->3个 就是1,2,3,但是1,2之前已经出现,所以是 1*1!
将所有乘积相加=7
比该数小的数有7个,所以该数排第8的位置。
1234 1243 1324 1342 1423 1432
2134 2143 2314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321
//康托展开
LL Work(char str[])
{
int len = strlen(str);
LL ans = 0;
for(int i=0; i<len; i++)
{
int tmp = 0;
for(int j=i+1; j<len; j++)
if(str[j] < str[i]) tmp++;
ans += tmp * f[len-i-1]; //f[]为阶乘
}
return ans; //返回该字符串是全排列中第几大,从1开始
}
逆运算的方法:
假设求4位数中第19个位置的数字。
① 19减去1 → 18
② 18 对 3! 作除法 → 得3余0
③ 0对 2! 作除法 → 得0余0
④ 0对 1! 作除法 → 得0余0
据上面的可知:
我们第一位数(最左面的数),比第一位数小的数有3个,显然 第一位数为→ 4
比第二位数小的数字有0个,所以 第二位数为→1
比第三位数小的数字有0个,因为1已经用过,所以第三位数为→2
第四位数剩下 3
该数字为 4123 (正解)
//康托逆展开
void reverse_contor(int x){
memset(vis,0,sizeof vis);
x--;
int j;
for(int i=1;i<=n;i++){
int t=x/fac[n-i];
for(j=1;j<=n;j++){
if(!vis[j]){
if(!t) break;
t--;
}
}
printf("%d ",j);
vis[j]=1;
x%=fac[n-i];
}
puts("");
}
【康托展开例题】
CSU-1828
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<cctype>
#include<stack>
#include<sstream>
#include<list>
#include<assert.h>
#include<bitset>
#include<numeric>
#define debug() puts("++++")
#define gcd(a,b) __gcd(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a,b,sizeof(a))
#define sz size()
#define be begin()
#define mp make_pair
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define rep(i,x,n) for(int i=(x); i<(n); i++)
#define reps(i,x,n) for(int i=(x); i<=(n); i++)
#define sf scanf
#define pf printf
#define in freopen("in.in","r",stdin)
#define out freopen("out.out","w",stdout)
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const ULL base = 100000007;//33951943
const int INF = 0x3f3f3f3f;
const ll LNF = 9997;
const int maxn = 1e5+50;
const int maxm = 1e5 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int dx[] = {-1,1,0,0,1,1,-1,-1};
const int dy[] = {0,0,1,-1,1,-1,1,-1};
int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
ll fac[11];
char s[10];
int n,m,p;
int main()
{
int T;
fac[1]=1;
rep(i,2,10) fac[i]=fac[i-1]*i;
sf("%d",&T);
while(T--)
{
sf("%s",s);
ll res=0;
rep(i,0,9)
{
ll tmp=0;
rep(j,i+1,9)
{
if(s[j]<s[i]) tmp++;
}
res+=tmp*fac[9-i-1];
}
pf("%lld\n",res+1);
}
return 0;
}
/*
【题意】
【类型】
【分析】
【时间复杂度&&优化】
【trick】
【数据】
*/
康托展开&逆展开算法笔记的更多相关文章
- 康托展开+逆展开(Cantor expension)详解+优化
康托展开 引入 康托展开(Cantor expansion)用于将排列转换为字典序的索引(逆展开则相反) 百度百科 维基百科 方法 假设我们要求排列 5 2 4 1 3 的字典序索引 逐位处理: 第一 ...
- 康托展开&逆康托展开学习笔记
啊...好久没写了...可能是最后一篇学习笔记了吧 题目大意:给定序列求其在全排列中的排名&&给定排名求排列. 这就是康托展开&&逆康托展开要干的事了.下面依次介绍 一 ...
- 【数学】康托展开 && 康托逆展开
(7.15)康托展开,就是把全排列转化为唯一对应自然数的算法.它可以建立1 - n的全排列与[1, n!]之间的自然数的双向映射. 1.康托展开: 尽管我并不清楚康托展开的原理何在,这个算法的过程还是 ...
- HDU 1027 Ignatius and the Princess II(康托逆展开)
Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ( ...
- 康托展开&&康托逆展开
康托展开 简介:对于给定的一个排列,求它是第几个,比如54321是n=5时的第120个.(对于不是1~n的排列可以离散化理解) 做法: ans=a[n]*(n-1)!+a[n-1]*(n-2)!+~~ ...
- 康托展开&康托逆展开 的写法
康托展开 康托展开解决的是当前序列在全排序的名次的问题. 例如有五个数字组成的数列:1,2,3,4,5 那么1,2,3,4,5就是全排列的第0个[注意从0开始计数] 1,2,3,5,4就是第1个 1, ...
- 康拓展开 & 逆康拓展开 知识总结(树状数组优化)
康拓展开 : 康拓展开,难道他是要飞翔吗?哈哈,当然不是了,康拓具体是哪位大叔,我也不清楚,重要的是 我们需要用到它后面的展开,提到展开,与数学相关的,肯定是一个式子或者一个数进行分解,即 展开. 到 ...
- CornerNet-Lite算法笔记
论文名称:CornerNet-Lite: Efficient Keypoint Based Object Detection 论文链接:https://arxiv.org/abs/1904.08900 ...
- 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)
Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...
随机推荐
- 【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap
题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义 ...
- JAVA List 一边遍历一边删除元素
JAVA List 一边遍历一边删除元素,报java.util.ConcurrentModificationException异常 2015年02月10日 14:42:49 zhanzkw 阅读数:3 ...
- Ubuntu下安装LNMP之nginx的安装
Nginx 最初是作为一个 Web 服务器创建的,用于解决 C10k 的问题.作为一个 Web 服务器,它可以以惊人的速度为您的数据服务.但 Nginx 不仅仅是一个 Web 服务器,你还可以将其用作 ...
- [uva 1350]数位dp+二分
题目链接:https://vjudge.net/problem/38405 #include<bits/stdc++.h> using namespace std; ][]; ]; lon ...
- spring中@PropertySource注解的使用
概述: The @PropertySource annotation provides a convenient and declarative mechanism for adding aPrope ...
- bzoj2424 [HAOI2010]订货 dp+单调性
[HAOI2010]订货 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1311 Solved: 884[Submit][Status][Discu ...
- 使用vue做移动app时,调用摄像头扫描二维码
现在前端技术发展飞快,前端都能做app了,那么项目中,也会遇到调用安卓手机基层的一些功能,比如调用摄像头,完成扫描二维码功能 下面我就为大家讲解一下,我在项目中调用这功能的过程. 首先我们需要一个中间 ...
- webpack 的第三方库分离并持久化缓存
我们常常需要在浏览器缓存一些稳定的资源,如第三方库等.要达到这个目标,只需要两步: 1.提取出“稳定的资源”: 2.提供稳定的文件hash . 处理后的出的文件就像这样子: app.1w3ad4q4. ...
- POJ 1064---二分搜索法
///2.假定一个解并判断是否可行 ///POJ1064 /** Q:有N条绳子,长度分别为Li,从中切割出k条长度相同的绳子, 这K条绳子最长能有多长?保留两位小数 A: 二分搜索模型. 条件C(x ...
- [转]华 使用npm安装一些包失败了的看过来(npm国内镜像介绍)
发布于 5 年前 作者 wppept 275957 次浏览 最后一次编辑是 1 年前 这个也是网上搜的,亲自试过,非常好用! 镜像使用方法(三种办法任意一种都能解决问题,建议使用第三种,将配置 ...