首页 > 其他分享 >【组合数学】康托展开 学习笔记

【组合数学】康托展开 学习笔记

时间:2023-07-18 17:24:22浏览次数:51  
标签:第一位 排列 int 第三位 笔记 数学 字典 康托

康托展开

将 \(1...n\) 的所有排列按照字典序进行排序,某个排列的排名可以通过康托展开的方法求出。

原理

观察排列 \(2,3,1,4\) 和 \(2,3,4,1\),发现第一个不同的位置是第三位,而且第一个排列的第三位比第二个小,根据字典序的性质,第一个排列的排名在第二个之前。

从这里我们也可以发现判断某个排列排名之前的排列数量的方法。对于 \(2,3,4,1\) 这个排列,我们逐位分析:

  • 第一位:\(2\),我们根据分类加法计数原理对所有排列进行分类:
    • 如果一个排列的第一位是 \(1\),则后面三位可以任意排列,有 \(3!\) 种情况。
    • 如果一个排列的第一位是 \(3,4\),显然后面如何排列都不满足条件。
    • 如果一个排列的第一位是 \(2\),分为下一类。
  • 第二位:\(3\),我们再对第一位是 \(2\) 的排列进行分类:
    • 第二位是 \(1\),后面的两个数可以任意排列,有 \(2!\) 种情况。
    • 第二位是 \(4\),显然后面如何排列都不满足条件。
    • 第二位是 \(3\),分为下一类
  • 第三位:\(4\):我们对前两位是 \(2,3\) 的排列进行分类:
    • 第三位是 \(1\) 对答案产生 \(1!\) 的贡献。
    • 第三位是 \(4\) 则是排列 \(2,3,4,1\)。

所以,最终的答案就是 \(1*3! + 1*2! + 1*1! = 9\),有 \(9\) 个排列的字典序比这个排列小,所以这个排列的排名是 \(10\)。

由此可得比某排列的字典序小的排列数量:

\[\sum_{i=1}^{n}(c_{a[i]} \times (n-i)!) \]

其中,\(c_{a[i]}=\sum_{j=i}^n [a[j]<a[i]]\),表示第 \(i\) 个数后面比 \(a[i]\) 小的数,可以用树状数组计算。

代码实现

洛谷 P5367 【模板】康托展开

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 1e6 + 5, mod = 998244353;

int n, a[N];

int jc[N];

int t[N], ca[N];

int ans = 0;

void add(int id) {
    for (int i = id;i <= n;i += (i & (-i))) t[i]++;
}

int query(int id) {
    int ret = 0;
    for (int i = id;i;i -= (i & (-i))) ret += t[i];
    return ret;
}

signed main() {
    ios::sync_with_stdio(0);
    #ifdef DEBUG
    clock_t t0 = clock();
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    #endif

    // Don't stop. Don't hide. Follow the light, and you'll find tomorrow. 

    cin >> n;
    for (int i = 1;i <= n;i++) cin >> a[i];

    jc[0] = 1;
    for (int i = 1;i <= n;i++) jc[i] = (jc[i - 1] * i) % mod;

    for (int i = n;i;i--) {
        ca[i] = query(a[i]);
        add(a[i]);
    }

    for (int i = 1;i <= n;i++) {
        ans = (ans + ca[i] * jc[n - i]) % mod;
    }

    cout << ans + 1 << endl;

    #ifdef DEBUG
    cerr << "Time used:" << clock() - t0 << "ms" << endl;
    #endif
    return 0;
}

参考资料 && 推荐题目

  1. 康托展开 - OI Wiki

标签:第一位,排列,int,第三位,笔记,数学,字典,康托
From: https://www.cnblogs.com/JXOIer-zaochen/p/17563560.html

相关文章

  • jfinal 框架学习笔记-第四天 view的相应学习
    一.view页面的一次指令运用  页面上的一些语法:   二。另一种view显示<hr><hr><hr>#set(x=123)#(x)<hr><hr><hr>效果如下: 整体代码: 三。引用页面 ......
  • 零基础入门——从零开始学习PHP反序列化笔记(二)
    魔术方法魔术方法介绍__construct()触发时机:实例化对象之前构造函数,在实例化一个对象的时候,首先会去自动执行的一个方法;<?phpclassUser{public$username;publicfunction__construct($username){$this->username=$username;echo"......
  • 组合数学相关
    组合数学相关约定:无特殊说明,以下字母所代表的数均为非负整数。一些符合及其含义\(n!:=1\times2\times3\times…\timesn\),特别地,\(0!=1\)$\binom{n}{m}=\frac{n!}{m!(n-m)!}$,表示\(n\)个数无顺序选出\(m\)个数的方案数,称作组合数。$n\brackm$a.k.a$......
  • jfinal 框架学习笔记-第三天 Model相关学习--record+Model增删改查的用法(震惊之今日刷
    1.了解了数据库连接池。其中使用最多也是最广泛的是druid数据库连接池也就是阿里云研发的数据库连接池2.ActiveRecord(jFinal的核心技术)+DruidPlugin(数据库连接词,如何与数据库打交道)ActiveRecord:1.Record(记录,相当于一个通用的Model),2.Model(提供日常CRUD的封装)Model示例......
  • 复杂最短路做题笔记
    1.CF609EMinimumspanningtreeforeachedgeluogu传送门CodeForces传送门题意给你\(n\)个点,\(m\)条边,对于编号位i的边求出必须包含i的最小生成树权值和。很好理解,不做赘述。题解前置芝士:Kruskal算法求最小生成树,ST表倍增。首先,我们不考虑每条边的限制,先将整张图的......
  • win10小狼毫配置实操笔记
    下载安装进入官方网站下载最新版小狼毫,安装后选择朙(明)月拼音。在配置前阅读官方文档有关用户文件夹和共享文件夹的介绍。default.yaml用来调试全局方案,定制该文件后切换其他比如五笔、双拼等方案时,其定制内容依旧适用。weasel.yaml用来修改rime的常规设置,定制外观。symbol......
  • [论文笔记] Line-CNN: End-to-End Traffic Line Detection With Line Proposal Unit
    IEEETITS2019YangJianlastupdate:2023/07/17简介作者受Faster-RCNN启发,提出Line-CNN,提出了一种新颖的车道线Anchor的表示方法,解决了车道线检测中表征的难点,实现了端到端的车道线检测.车道线是一条曲线,所以无法使用常规检测中矩形bbox作为Anchor,为了用Anchor来......
  • MIT6.S081学习笔记--lec 1
    引言操作系统的目标abstractH/W抽象化硬件multiplex多路复用isolation隔离性sharing共享(进程通信,数据共享)security/accesscontrol安全性/权限控制performance性能/内核开销rangeofapplications多应用场景操作系统概览操作系统应该提供的功能:1.多进程支......
  • TransE 学习笔记
    目录TransEWhatisTransE?MotivationTransE算法过程输入参数训练过程实验小结TransEpaper:TranslatingEmbeddingsforModelingMulti-relationalDataTransE是由AntoineBordes发表于2013年的NIPS(现NeurIPS)上的工作,众所周知这篇文章是知识图谱表示学习的开山之作,......
  • 数据结构练习笔记——删除单链表中相同元素
    删除单链表中相同元素【问题描述】单链表中存放了若干整数,请删除相同整数。【输入形式】单链表【输出形式】删除相同整数后的单链表【样例输入】11123【样例输出】123【样例说明】递增的形式输入数据,允许相同元素#include<stdlib.h>#include<iostream>usingname......