CF501D Misha and Permutations Summation(康托展开)
将一个排列映射到一个数的方法就叫做康托展开。它的具体做法是这样的,对于一个给定的排列{ai}(i=1,2,3...n),对于每个ai求有多少个aj,使得j>i且ai>aj,简单来说就是求ai后面有多少数比ai小,假设我们求出来了这样的排列的一个对应数组{bi},其中bi就是ai后面有多少个数比它小。那么这个排列对应的康托展开即为∑bi*(n-i)!.
ai={1 3 5 4 2}
bi={0 1 2 1 0} 对应的排列数 0*4!+1*3!+2*2!+1*1!+0*0!.
bi可以通过树状数组在O(nlogn)里得到。
至于逆康托展开,就是已知bi,反求出ai,即知道了{0 1 2 1 0}.
做法也是类似的,我们看第一个数是0,表示后面有0个比它小的数,那么它必然是1.然后看第二个数是1,表示这个数在除去1 后面有1个比它小的数,那么这个数就是3,然后2,表示这个数后面在除去1,3,之后有2个比它小的数,所以它是5,以此往下。
一个O(nlogn)的想法是这样的,建立一棵平衡树,把1~n都插进去,每次查找第(bi+1)大的数,即为第i个数,然后把这个数删掉,以此往复。
但手写一个支持找第k大的平衡树比较慢,另外一个想法是在bit里把每个数都置1,然后二分出第一个使得前缀和为bi+1的数,这样做的复杂度就变成了O(nlog^2n).
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std; #define maxn 210000 int bit[maxn];
int n; void upd(int i)
{
while (i <= n){
bit[i] += 1;
i += i&(-i);
}
} void dec(int i)
{
while (i <= n){
bit[i] -= 1;
i += i&(-i);
}
} int cal(int i)
{
int ret = 0;
while (i > 0){
ret += bit[i];
i -= i&(-i);
}
return ret;
} int solve(int x)
{
int l = 1, r = n+1;
while (l < r)
{
int mid = (l + r) >> 1;
int tx = cal(mid);
if (tx < x) l = mid + 1;
else r = mid;
}
return l;
} int a[maxn];
int b[maxn];
int c[maxn];
int va[maxn];
int vb[maxn];
int vc[maxn]; int main()
{
while (cin >> n)
{
for (int i = 0; i < n; ++i){
scanf("%d", a + i); a[i]++;
}
for (int i = 0; i < n; ++i){
scanf("%d", b + i); b[i]++;
}
memset(bit, 0, sizeof(bit));
for (int i = n - 1; i >= 0; --i){
va[i] = cal(a[i]);
upd(a[i]);
}
memset(bit, 0, sizeof(bit));
for (int i = n - 1; i >= 0; --i){
vb[i] = cal(b[i]);
upd(b[i]);
}
reverse(va, va + n);
reverse(vb, vb + n);
memset(vc, 0, sizeof(vc));
int carry = 0;
for (int i = 1; i < n; ++i){
vc[i] = (carry + va[i] + vb[i]) % (i + 1);
carry = (carry + va[i] + vb[i]) / (i + 1);
}
reverse(vc, vc + n);
memset(bit, 0, sizeof(bit));
for (int i = 1; i <= n; ++i){
upd(i);
}
for (int i = 0; i < n; ++i){
c[i] = solve(vc[i]+1);
dec(c[i]);
}
for (int i = 0; i < n; ++i){
if (i) printf(" ");
printf("%d", c[i]-1);
}
puts("");
}
return 0;
}
CF501D Misha and Permutations Summation(康托展开)的更多相关文章
- Codeforces Round #285 (Div. 1) B - Misha and Permutations Summation 康拓展开+平衡树
思路:很裸的康拓展开.. 我的平衡树居然跑的比树状数组+二分还慢.. #include<bits/stdc++.h> #define LL long long #define fi fir ...
- Misha and Permutations Summation
A - Misha and Permutations Summation 首先这个 mod n! 因为数量级上的差别最多只会对康拓展开的第一项起作用所以这个题并不需要把 ord (p) 和 ord ( ...
- [Codeforces 501D] - Misha and Permutations Summation
题意是给你两个长度为$n$的排列,他们分别是$n$的第$a$个和第$b$个全排列.输出$n$的第$\left(a+b \right)\textrm{mod} \, n!$个全排列. 一种很容易的想法是 ...
- 【codeforces 501D】Misha and Permutations Summation
[题目链接]:http://codeforces.com/problemset/problem/501/D [题意] 给你两个排列; 求出它们的字典序num1和num2; 然后让你求出第(num1+n ...
- Codeforces Round #285 (Div.1 B & Div.2 D) Misha and Permutations Summation --二分+树状数组
题意:给出两个排列,求出每个排列在全排列的排行,相加,模上n!(全排列个数)得出一个数k,求出排行为k的排列. 解法:首先要得出定位方法,即知道某个排列是第几个排列.比如 (0, 1, 2), (0, ...
- 用康托展开实现全排列(STL、itertools)
康拓展开: $X=a_n*(n-1)!+a_{n-1}*(n-2)!+\ldots +a_2*1!+a_1*0!$ X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+ ...
- leetcode 60. Permutation Sequence(康托展开)
描述: The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of t ...
- 【BZOJ】3301: [USACO2011 Feb] Cow Line(康托展开)
http://www.lydsy.com/JudgeOnline/problem.php?id=3301 其实这一题很早就a过了,但是那时候看题解写完也是似懂非懂的.... 听zyf神犇说是康托展开, ...
- UVA11525 Permutation[康托展开 树状数组求第k小值]
UVA - 11525 Permutation 题意:输出1~n的所有排列,字典序大小第∑k1Si∗(K−i)!个 学了好多知识 1.康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+ ...
随机推荐
- 传送流(TS)的基础知识
数字电视的TS包和TS流的组成和功能 综合考虑几下几个因素: (1)包的长度不能过短,否则包头开销所占比例过大, 导致传输效率下降 (2)包的长度不能过长,否则在丢失同步的情况下恢复同步的 周期过长, ...
- excel VBA 将文本数值转换为数字格式(单元格中数据左上角是绿三角,鼠标点上有叹号标示)
Range("A6").SelectSelection.CopyRange("A10:A60").SelectRange(Selection, Selectio ...
- Python 日常报错总结
本章内容 requests模块报错 执行:res = requests.post(api,mdata = post_data) 报错:SSLError: EOF occurred in violati ...
- mac攻略(八) -- 神器zsh和iterm2的配置
1. 安装oh my zsh 安装命令: curl -L http://install.ohmyz.sh | sh 修改shell的方式: chsh -s /bin/zsh 2.安装cask( ...
- 5个最佳的Android测试框架(带示例)
谷歌的Android生态系统正在不断地迅速扩张.有证据表明,新的移动OEM正在攻陷世界的每一个角落,不同的屏幕尺寸.ROM /固件.芯片组以及等等等等,层出不穷.于是乎,对于Android开发人员而言 ...
- Google Chrome开发者工具-移动仿真:触摸事件仿真
如果你在开发PAD/手机所用WEB版应用,需要在桌面审查页面元素.调试脚本,模拟移动设备尺寸.事件.位置等信息, 那么可以使用Chrome开发者工具(DevTools)提供的强大的移动仿真功能,支持主 ...
- 微信小程序-----校园头条整体概括
1.项目需求 为了让在校师生可以更加方便的了解学校信息,从而合理的安排自己的时间,避免发生冲突和错过事件,通过小程序的便利性,可以达到随手一查的功能. 2.项目布局 3.效果展示 3.1登录 3.2首 ...
- [转载]用等高线图(Contour maps)可视化多变量函数
https://blog.csdn.net/xlinsist/article/details/50920479 Overview 由于我们用手来画三维图像很困难,我们可以用等高线图来描述图像会更加简单 ...
- centos7下使用git
问:为什么需要版本控制系统?[转:http://www.cnblogs.com/shenliang123/p/3824383.html] 版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情 ...
- C#中静态变量和 静态方法的作用
1.静态变量 在C#程序中,没有全局变量的概念,这意味着所有的成员变量只有该类的实例才能操作这些数据,这起到了“信息隐藏”的作用.但有些时候,这样做却不是个明智的选择. 假设我们要定义一个图书类,要求 ...