[洛谷]P5367【模板】康托展开
时间:2020-04-12
本文章向大家介绍[洛谷]P5367【模板】康托展开,主要包括[洛谷]P5367【模板】康托展开使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目
题目
康托展开,用于给你一个排列,让你求出这个排列是字典序的第几个全排列。
这么说比较抽象,我们举个例子。
比如给你一个排列\([2,1,3]\),这个排列是第几个全排列呢?
我们知道,1~3的排列有六种,是\([1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]\),\([2,1,3]\)按照字典序在第三个,所以是第三个全排列。
康托展开就是用来求这个东西的。
题解
比如,输入\([2,1,4,3]\),易得输出是8,那么怎么使用康托展开来做呢?我们一项一项来看。
s记录输出,初始为0。
首先第一项是2,第一项如果填1的话有3!=六种排列,所以第一位填2就肯定在6以上了,s+=6。
第二项是1,没什么用,不管它。
第三项是4,由于1,2已经填过了,所以4的前面只有3,第三项如果填3的话有1!=1种排列,s+=1。
最后一项有0!=1种排列,s+=1。
最后s=8。
最后给出通式:\(rank=A_n(n-1)!+A_{n-1}(n-2)!+...+a_10!\)
\(A_i=\sum_{j=i}^n[a[j]<a[i]]\)
那么怎么判断填过呢?笔者还没有想到线性的算法,只好写了个树状数组。
#include <iostream>
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
const ll N=1E6+10,M=998244353;
ll a[N],c[N],n;
void add(int x) {
while(x<=n) {
c[x]++;
x+=lowbit(x);
}
}
ll get(int x) {
ll res=0;
while(x) {
res+=c[x];
x-=lowbit(x);
}
return res;
}
int main() {
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
ll s=1;
ll frac=1;
for(int i=n;i>=1;i--) { //反着递推,这样子好求阶乘取模
ll k=get(a[i]);
s=(s+frac*k)%M;
frac=(frac*(n-i+1))%M;
add(a[i]);
}
cout<<s;
return 0;
}
原文地址:https://www.cnblogs.com/wyc06/p/12687596.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法