题解 P5367 【【模板】康托展开】
P5367 【模板】康托展开
感觉这题难度大概在绿题到蓝题之间qwq
一、洛谷日报[yummy]浅谈康托展开
如我想知道321是{1,2,3}中第几个小的数可以这样考虑 :
第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2× 2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1× 1!=1 所以小于321的{1,2,3}排列数有2×2!+1×1!=5个。所以321是第6个小的数。 2 ×2!+1× 1!+0× 0!就是康托展开。
再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0× 3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2,1×2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0×1! ,所以比1324小的排列有0×3!+1× 2!+0×1 !=2个,1324是第三个小数。(摘自百度)
暴力做法
//n表示全排列长度
for(int i=1;i<=n;i++)
{
cin>>a[i];
int x=a[i];
for(int j=1;j<=a[i];j++)
x-=used[j];
//used[j]表示j是否用过(1用过,0没用)
used[a[i]]=1;
a[i]=x-1;
}
二、优化
“我们看到,刚才的方法有两重循环,时间复杂度为 O(N^2) ,找左侧用过的数的数量很费时间。
只要把used函数用线段树或树状数组维护区间和,就可以只花log的时间就求出左侧小于自己的数的个数了。” (摘自日报)
三、代码
#include<cstdio>
using namespace std;
#define N 1000001
int n,tr[N];
long long ans,fac[N];
inline void add(int x,int k) {
for (; x<=n; x+=x&-x) tr[x]+=k;
}
inline int query(int x) {
int t=0;
for (; x; x-=x&-x) t+=tr[x];
return t;
}
int main() {
scanf("%d",&n);
fac[0]=1;
for (int i=1; i<=n; i++) {
fac[i]=fac[i-1]*i%998244353;
add(i,1);
}
for (int i=1,x; i<=n; i++) {
scanf("%d",&x);
ans=(ans+(query(x)-1)*fac[n-i])%998244353;
add(x,-1);
}
printf("%lld",ans+1);
return 0;
}
四、拓展:逆康托展开
例 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
(1)找出第96个数
首先用96-1得到95
用95去除4! 得到3余23
有3个数比它小的数是4
所以第一位是4
用23去除3! 得到3余5
有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
用5去除2!得到2余1
有2个数比它小的数是3,第三位是3
用1去除1!得到1余0
有1个数比它小的数是2,第二位是2
最后一个数只能是1
所以这个数是45321(摘自百度)
题解 P5367 【【模板】康托展开】的更多相关文章
- 洛谷 P5367 【模板】康托展开(数论,树状数组)
题目链接 https://www.luogu.org/problem/P5367 什么是康托展开 百度百科上是这样说的: “康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩. ...
- [洛谷P5367]【模板】康托展开
题目大意:给定一个$n$的排列,求它在$n$的全排列中的名次 题解:康托展开,对于一个全排列,第$i$为有$n+1-i$种选择,用变进制数表示,这一位就是$n+1-i$进制.记排列中第$[1,i)$中 ...
- 2021.08.05 P5357 康托展开模板(康托展开)
2021.08.05 P5357 康托展开模板(康托展开) P5367 [模板]康托展开 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.康托展开 算法学习笔记(56): ...
- HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- LG5367 「模板」康托展开 康托展开
问题描述 LG5367 题解 康托展开公式: \[ans=1+(\sum_{i=1}^{n}{a_i})\times(n-i)!\] 用树状数组维护一下\(\sum\)里面的东西,前缀积维护后面的东西 ...
- 题解报告:NYOJ 题目139 我排第几个(康托展开)
描述 现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=1 ...
- 题解报告:NYOJ 题目143 第几是谁?(逆康托展开)
描述 现在有"abcdefghijkl”12个字符,将其按字典序排列,如果给出任意一种排列,我们能说出这个排列在所有的排列中是第几小的.但是现在我们给出它是第几小,需要你求出它所代表的序列. ...
- LOJ167 康托展开 题解
题面 康托展开: 康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩. 康托展开的实质是计算当前排列在所有由小到大全排列中的名次,因此是可逆的. X = A[0] * (n-1)! ...
- 康托展开+逆展开(Cantor expension)详解+优化
康托展开 引入 康托展开(Cantor expansion)用于将排列转换为字典序的索引(逆展开则相反) 百度百科 维基百科 方法 假设我们要求排列 5 2 4 1 3 的字典序索引 逐位处理: 第一 ...
随机推荐
- Newtonsoft.Json高级用法之枚举中文转义
最近看博客园中 焰尾迭的两篇关于"Newtonsoft.Json高级用法"的文章受到了很多人的评论,一度登入到头条推荐. 今天我就不再重复焰尾迭博文中的一些提过的Newtonsof ...
- virtualbox ubuntu16.04 自动挂载共享文件夹
为了操作方便,需要ubuntu 在开机运行时自动挂载共享文件夹,ubuntu的版本是16.04,宿主机是win10,步骤如下: 1. 在virtualbox “设备”-“共享文件夹”中设置共享文件夹如 ...
- Qt多线程学习-用例子来理解多线程
文章出处:DIY部落(http://www.diybl.com/course/3_program/c/c_js/20090303/157373_3.html) POINT 1:QThread类的实例与 ...
- R3 HOOK OpenProcess 的问题
unit HookAPI; //Download by http://www.codefans.net interface uses Windows, Classes; function Locate ...
- 分布式存储系统GlusterFS初体验
摘要: GlusterFS是Scale-Out存储解决方案Gluster的核心,它是一个开源的分布式文件系统,具有强大的横向扩展能力,通过扩展能够支持数PB存储容量和处理数千客户端.GlusterFS ...
- Silverlight ItemsControl详细解析+解惑
Silverlight最强大的地方就在于定义控件了,Silverlight提供了非常灵活和高效的控件定义方式,几乎可以实现任何复杂的控件实现,对于快速开发应用程序有着重要的意义.在Silverligh ...
- Awesome Go (http://awesome-go.com/)
A curated list of awesome Go frameworks, libraries and software. Inspired by awesome-python. Contrib ...
- spring boot单元测试之RestTemplate(一)
写代码重要,写好的代码准确无误,且符合预期那更是必不可少. spring boot内嵌了专门的单元测试模块——RestTemplate,保证了程序员可以对自己的代码进行及时的测试. 闲言少叙,直接上代 ...
- 面试还不知道BeanFactory和ApplicationContext的区别?
接口 BeanFactory 和 ApplicationContext 都是用来从容器中获取 Spring beans 的,但是,他们二者有很大不同 我看到过很多问 BeanFactory 和 App ...
- Hadoop 学习之路(七)—— HDFS Java API
一. 简介 想要使用HDFS API,需要导入依赖hadoop-client.如果是CDH版本的Hadoop,还需要额外指明其仓库地址: <?xml version="1.0" ...