这三个题的代码分别对应第二个第一个第三个

在刘汝佳蓝书上我遇到了这个康托展开题。

当时去了解了一下,发现很有意思

百度上的康托展开定义

原理介绍

编辑

康托展开运算

其中,

为整数,并且

的意义为在ai之后出现的数有几个比他小

康托展开的逆运算

既然康托展开是一个双射,那么一定可以通过康托展开值求出原排列,即可以求出n的全排列中第x大排列。
如n=5,x=96时:
首先用96-1得到95,说明x之前有95个排列.(将此数本身减去1)用95去除4! 得到3余23,说明有3个数比第1位小,所以第一位是4.用23去除3! 得到3余5,说明有3个数比第2位小,所以是4,但是4已出现过,因此是5.用5去除2!得到2余1,类似地,这一位是3.用1去除1!得到1余0,这一位是2.最后一位只能是1.所以这个数是45321。
按以上方法可以得出通用的算法。 [1] 
 
此定理的证明十分简易,就是用组合原理
我们能明白第k位上的数码若为x则有(n-k-1)!(x-1)种比他小的排列(字典序小)
就可以证了
 
 
显然,n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出唯一的一个排列。
 
 
我们可以发现正着求的话,阶乘on预处理,那么关键就在于ai怎么求。
我们观察到暴力是on2
如果把数变为布尔数组
转化问题为一般二位偏序
用树状数组求前面0的个数
不就是ai了么
所以就可以nlogn求解
 
发下暴力(洛谷2524)

 #include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define mod 19260817
int n,m,a,b,c,ans=,list[],visit[];
void makelist(){
list[]=;
for(int i=;i<=;i++)
list[i]=(list[i-]%mod)*i%mod;
}
string s;
int main(){
cin>>n;
memset(visit,,sizeof(visit));
makelist();
cin>>s;
for(int i=;i<s.length();i++){
a=s[i]-'';visit[a]=;
m=;
for(int j=;j<a;j++){
if(!visit[j])m++;
}
ans+=list[n--i]*m;
}
cout<<ans+;
return ;
}

轮到正解了(bzoj3301)

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define mod 19260817
int n,m,a,b,c,ans=,list[],input[],tree[];
int lowbit(int x){return x&(-x);}
int query(int x){int ans=;for(int i=x;i>;i-=lowbit(i))ans+=tree[i];return ans;}
void add(int p,int x){for(int i=p;i<=n;i+=lowbit(i))tree[i]+=x;}
void makelist(){
list[]=;
for(int i=;i<=;i++)
list[i]=(list[i-]%mod)*i%mod;
}
int main(){
cin>>n;
makelist();
for(int i=;i<=n;i++)
cin>>input[i];
for(int i=;i<=n;i++){
a=input[i];add(a,);
m=a-query(a);
ans+=list[n-i]*m;
}
cout<<ans+;
return ;
}

那逆运算呢

由于我们知道ai<n

所以我们观察到(n-i)!*ai<n!

可以推出x/(n-i)!=ai;(下取整)

问题转化为二位偏序,前缀第k大

就可以用树状数组解决(也可以用主席树)

代码参考的candy博主

uva1125
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=5e5+,INF=1e6+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int n,x,k;
int c[N];
inline int lowbit(int x){return x&-x;}
inline void add(int p,int v){
for(;p<=n;p+=lowbit(p)) c[p]+=v;
}
inline int sum(int p){
int res=;
for(;p>;p-=lowbit(p)) res+=c[p];
return res;
}
inline int kth(int k){
int x=,cnt=;
for(int i=;i>=;i--){
x+=(<<i);
if(x>=n||cnt+c[x]>=k) x-=(<<i);
else cnt+=c[x];
}
return x+;
}
int main(){
int T=read();
while(T--){
n=read();
memset(c,,sizeof(c));
for(int i=;i<=n;i++) add(i,);
for(int i=;i<=n;i++){
k=read()+;
x=kth(k);
cout<<x<<" ";
add(x,-);
}
}
}

BZOJ3301 P2524 UVA11525 算法解释康托展开的更多相关文章

  1. [算法总结]康托展开Cantor Expansion

    目录 一.关于康托展开 1.什么是康托展开 2.康托展开实现原理 二.具体实施 1.模板 一.关于康托展开 1.什么是康托展开 求出给定一个由1n个整数组成的任意排列在1n的全排列中的位置. 解决这样 ...

  2. POJ 1077 && HDU 1043 Eight A*算法,bfs,康托展开,hash 难度:3

    http://poj.org/problem?id=1077 http://acm.hdu.edu.cn/showproblem.php?pid=1043 X=a[n]*(n-1)!+a[n-1]*( ...

  3. 【算法进阶-康托展开】-C++

    目录 引入 这位老爷子就是康托 基本概念 康托展开是一个全排列到一个自然数的双射,常用于构建hash表时的空间压缩.设有n个数(1,2,3,4,-,n),可以有组成不同(n!种)的排列组合,康托展开表 ...

  4. 数学【P2524】 Uim的情人节礼物·其之弐 (康托展开)

    因为某人@ZAGER挖坑让我讲一下康托展开,所以发现了这个题,顺便说一下康托展开是个什么东西 题目概括 给定n与一个数列,要求求出给定数列在n的全排列中的排名(按照字典序从小到大排列) 康托展开 先放 ...

  5. UVA11525 Permutation[康托展开 树状数组求第k小值]

    UVA - 11525 Permutation 题意:输出1~n的所有排列,字典序大小第∑k1Si∗(K−i)!个 学了好多知识 1.康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+ ...

  6. 康托展开&逆展开算法笔记

    康托展开(有关全排列) 康托展开:已知一个排列,求这个排列在全排列中是第几个 康托展开逆运算:已知在全排列中排第几,求这个排列 定义: X=an(n-1)!+an-1(n-2)!+...+ai(i-1 ...

  7. OJ 1188 全排列---康托展开

    题目描述 求n的从小到大第m个全排列(n≤20). 输入 n和m 输出 输出第m个全排列,两个数之间有一空格. 样例输入 3 2 样例输出 1 3 2 #include<cstdio> # ...

  8. hdu1430魔板(BFS+康托展开)

    做这题先看:http://blog.csdn.net/u010372095/article/details/9904497 Problem Description 在魔方风靡全球之后不久,Rubik先 ...

  9. 洛谷P2525 Uim的情人节礼物·其之壱 [康托展开]

    题目传送门 Uim的情人节礼物·其之壱 题目描述 情人节到了,Uim打算给他的后宫们准备情人节礼物.UIm一共有N(1<=N<=9)个后宫妹子(现充去死 挫骨扬灰!). 为了维护他的后宫的 ...

随机推荐

  1. 记一次因证书问题导致请求失败问题SSLHandshakeException

    记一次因证书问题导致请求失败问题SSLHandshakeException 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/10989813.html 最近接一外 ...

  2. MyBatis源码解析(一)

    <!-- mybatis文件配置,扫描所有mapper文件 --><!--SqlSessionFactoryBean的初始化参数--> <bean id="sq ...

  3. win10怎么修改DNS

    方法/步骤   1 鼠标右键桌面单击此电脑--属性,如下图所示 2 进入电脑属性,选择控制面板主页,如下图所示 3 我们继续选择网络和Internet进入,如下图所示 4 进入网络和Internet, ...

  4. 清空模拟器中的app

    1.打开模拟器 2.在左上角得下拉菜单选择“还原内容和设置” 3.选择“还原” ,确定 就ok了! 图解如下:

  5. ItemsControl Grouping分组

    ItemsControl属性GroupStyle Grouping再ItemsControl源代码 public class ItemsControl : Control, IAddChild, IG ...

  6. Promise/A+规范

    1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...

  7. CF1149A Prefix Sum Primes

    思路: 质数一定是奇数.实现: #include <bits/stdc++.h> using namespace std; int main() { int n, t, x, y; whi ...

  8. 从零开始利用vue-cli搭建简单音乐网站(四)

    上一篇文章中说到这一篇博客会实现音乐播放功能,只是令我意外的是,如果利用h5的audio标签,几行代码就实现了......先来看一下最终效果吧. 这里直接用了audio标签,样式没有怎么管,能获得音乐 ...

  9. Random-数组

    1.能够使用Random生成随机数     1)import java.util.Random;         2)Random r = new Random();       3)r.nextIn ...

  10. fiddler+willow问题总结

    本文纯属用来记录自己学习过程中遇到的坑,如有朋友也遇到,可移步到这里查看是否为该问题导致. fiddler 安装不用说了,到官网直接去下载,自行下载最新版本 willow下载地址:http://qzo ...