Skip to content

504B

Description

Give you two permutations of n integers of 0 to n - 1. (1 \leq n \leq 2\times 10^5). Posit they are the ath and bth permutation. Output the (a + b) \% nth permutation.

Tutorial

With the thought of dynamic programming, we can come up with the formula of calculating the rank of a permutation, which is as follows. rank = \sum\limits_{i=1}^{n}{less(p_i) \times (n - i)!}. p_i is the ith number in the permutation. less(p_i) means the number of p_j which is less than p_i and j is greater than i, which can be calculated by binary indexed tree. With this formula we can calculate a+b like we add two big integers. less(p_i)s are the digits of the big integers. We need to do the carry bit.

After that we have the a+b and we need to transform it back to the a + bth permutation, which can be done by binary indexed tree and binary search.

Solution

#include <cstdio>
#include <algorithm>
using namespace std;

#define D(x) 

const int MAX_N = (int)(1e5) * 2 + 10;

int n;
int a[MAX_N];
int b[MAX_N];
int sum_b[MAX_N];
int sum_a[MAX_N];
int c[MAX_N];
int sum_c[MAX_N];

int binary_indexed_tree[MAX_N];

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

void add(int pos, int val)
{
    for (int i = pos; i < MAX_N; i += low_bit(i))
    {
        binary_indexed_tree[i] += val;
    }
}

int sum(int pos)
{
    int ret = 0;
    for (int i = pos; i > 0; i -= low_bit(i))
    {
        ret += binary_indexed_tree[i];
    }
    return ret;
}

void input(int a[])
{
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        a[i]++;
    }
}

void work(int sum_a[], int a[])
{
    fill(binary_indexed_tree, binary_indexed_tree + n + 1, 0);
    for (int i = n; i; i--)
    {
        sum_a[i] = sum(a[i]);
        add(a[i], 1);
    }
}

bool ok(int mid, int a)
{
    return sum(mid) >= a;
}

int binary_search(int start, int end, int a)
{
    int l = start;
    int r = end;
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (ok(mid, a))
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}

int main()
{
    //input
    scanf("%d", &n);
    input(a);
    input(b);

    //work
    work(sum_a, a);
    work(sum_b, b);
    for (int i = 1; i <= n; i++)
    {
        sum_c[i] = sum_a[i] + sum_b[i];
    }
    for (int i = n; i; i--)
    {
        if (sum_c[i] > n - i)
        {
            sum_c[i] -= n - i + 1;
            sum_c[i - 1] += 1;
        }
    }
    fill(binary_indexed_tree, binary_indexed_tree + n + 1, 0);
    for (int i = 1; i <= n; i++)
        add(i, 1);
    for (int i = 1; i <= n; i++)
    {
        c[i] = binary_search(1, n, sum_c[i] + 1);
        add(c[i], -1);
    }
    D(for (int i = 1; i <4; i++) printf("%d\n", sum_c[i]));

    //output
    for (int i = 1; i <= n; i++)
    {
        printf("%d", c[i] - 1);
        if (i != n)
            putchar(' ');
    }
    puts("");
    return 0;
}