码迷,mamicode.com
首页 > 其他好文 > 详细

[Codeforces 501D] - Misha and Permutations Summation

时间:2016-08-07 23:00:27      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:

题意是给你两个长度为$n$的排列,他们分别是$n$的第$a$个和第$b$个全排列。输出$n$的第$\left(a+b \right)\textrm{mod} \, n!$个全排列。

一种很容易的想法是直接把$a$和$b$求出来,然后计算$\left(a+b \right)\textrm{mod} \, n!$的值并直接求对应的排列,但是由于$n$的范围$\left(n\leq200000\right)$直接求值显然不可行。

因此,考虑全排列的康托展开(Cantor expansion) 任意一种排列在全排列中对应的序号为$$\sum_{i=1}^{n}{a}_{i}\times i!$$

于是,将输入的两个排列分别写成这种形式,然后遍历$n$相加,由于结果需要对$n!$取模,因此从最低位开始逐项将$a_i$加到$a_i+1$上去,最后将最高位的$a_n$模掉$n$即可。

之后,只要拟用康托展开即可求出对应的排列。

在实现过程中,由于需要维护"当前还没有使用过的第k大的数",因此可以用树状数组BIT维护。恢复排列时用树状数组+二分即可。

复杂度$\mathcal{O}({n\log}^{2}n )$

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define GETNUM(num) scanf("%d",&num)
#define IT_PT(BEG,END,TYPE,REG) copy(BEG,END,ostream_iterator<TYPE>(cout,REG))
#define CLR(ARR,NUM) memset(ARR,NUM,sizeof(ARR))
#define faster_io() ios_base::sync_with_stdio(false)
using namespace std;
const int MAXN = 200010;
int la[MAXN], lb[MAXN], a[MAXN], b[MAXN], f[MAXN], s[MAXN];
typedef int bit_type;
const int bit_maxn = MAXN;
int n;
int ff[MAXN];
bit_type tree[bit_maxn];

int lowbit(int x)
{
    return x & (-x);
}

void add(int x, int d)
{
    x++;
    while(x <= n) {
        tree[x] += d;
        x += lowbit(x);
    }
}

bit_type sum(int x)
{
    x++;
    bit_type ans = 0;
    while(x) {
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    cin >> n;
    for(int i = 0; i < n; i++)
        GETNUM(la[i]);
    for(int i = 0; i < n; i++)
        GETNUM(lb[i]);
    CLR(tree, 0);
    for(int i = 0; i < n; i++) {
        add(i, 1);
    }
    for(int i = 0; i < n; i++) {
        a[i] = sum(la[i] - 1);
        add(la[i], -1);
    }
    CLR(tree, 0);
    for(int i = 0; i < n; i++) {
        add(i, 1);
    }
    for(int i = 0; i < n; i++) {
        b[i] = sum(lb[i] - 1);
        add(lb[i], -1);
        s[i] = a[i] + b[i];
    }

    CLR(tree, 0);
    for(int i = 0; i < n; i++) {
        add(i, 1);
        ff[i] = 1;
    }
    for(int i = n - 1; i > 0; i--) {
        s[i - 1] += s[i] / (n - i);
        s[i] %= (n - i);
    }
    s[0] %= n;
    int rr = n - 1;
    for(int i = 0; i < n; i++) {
        int r = rr;
        int l = 0;
        while(l < r) {
            int mid = l + (r - l + 1) / 2;
            int t = sum(mid - 1);
            if(t <= s[i])	l = mid;
            else			r = mid - 1;
        }
        add(l, -1);
        ff[l] = 0;
        if(!i) {
            printf("%d", l);
        } else {
            printf(" %d", l);
        }
        while(!ff[rr]) {
            rr--;
        }
    }
    return 0;
}

 

[Codeforces 501D] - Misha and Permutations Summation

标签:

原文地址:http://www.cnblogs.com/KaitoHH/p/5747299.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!