CodeForces 501D Misha and Permutations Summation

题意:

n(2*10^5)个元素的排列有n!种  用Perm(x)表示字典序第x的序列(从0开始)  用Ord(排列y)表示排列y的字典序  现在输入排列p和q  求  Perm([Ord(p)+Ord(q)]%n!)

思路:

容易想到  对于第i位p[i]  如果它是第d小的数字  那么说明比它小的d-1个数字所产生的全排列都已经计数过了

例子  35142  第4位是4  它是第2小的(1和3出现过了)  那么35124这种情况一定已经计数了

因此我们可以分别对于p和q找出序列是排第几的  也就是Ord(p)和Ord(q)  那么根据这个过程的逆过程就可以做出Perm了

现在的难点在于n!这个数字太大了  不能计算

但是我们发现  我们感兴趣的东西都是阶乘!!  因此我们只需要记录(n-1)!  (n-2)!  ……  出现的次数  做完Ord(p)和Ord(q)之后将这个次数数组像模拟高精度一样扫一遍  就可以做出[Ord(p)+Ord(q)]%n!的结果了

我在做“查询第几小的数字”这个功能使用了二分+树状数组  因此复杂度为O(nlog^2n)

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long LL;
#define N 200010
#define lowbit(x) (x&(-x))

int n;
int a[N], b[N];
int f[N], c[N];

inline void scand(int &ret) {
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9')
        ;
    while (c >= '0' && c <= '9')
        ret = ret * 10 + (c - '0'), c = getchar();
}

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

int sum(int x) {
    int res = 0;
    while (x) {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

void init() {
    memset(c, 0, sizeof (c));
    for (int i = 1; i <= n; i++) add(i, 1);
}

int main() {
    scand(n);
    for (int i = 1; i <= n; i++) {
        scand(a[i]);
        a[i]++;
    }
    for (int i = 1; i <= n; i++) {
        scand(b[i]);
        b[i]++;
    }
    init();
    for (int i = 1; i < n; i++) {
        int les = sum(a[i] - 1);
        f[n - i] += les;
        add(a[i], -1);
    }
    init();
    for (int i = 1; i < n; i++) {
        int les = sum(b[i] - 1);
        f[n - i] += les;
        add(b[i], -1);
    }
    for (int i = 1; i < n; i++) {
        f[i + 1] += f[i] / (i + 1);
        f[i] = f[i] % (i + 1);
    }
    //    printf("F:\n");
    //    for (int i = 1; i <= n; i++)printf("%d ", f[i]);
    //    printf("\n");
    init();
    int sml = 1;
    for (int i = n - 1; i >= 1; i--) {
        int l = 1, r = n, mid, tmp, ans = -1;
        while (l <= r) {
            mid = (l + r) / 2;
            tmp = sum(mid - 1);
            if (tmp <= f[i]) {
                l = mid + 1;
                ans = mid;
            } else {
                //ans = mid;
                r = mid - 1;
            }
        }
        if (ans == -1) {
            ans = sml;
        }
        printf("%d ", ans - 1);
        add(ans, -1);
        while (!c[sml]) sml++;
        //        printf("C:\n");
        //        for (int i = 1; i <= n; i++)printf("%d ", c[i]);
        //        printf("\n");
        //        printf("sml %d\n", sml);
    }
    for (int i = 1; i <= n; i++) {
        if (c[i]) {
            printf("%d\n", i - 1);
            break;
        }
    }
    return 0;
}
时间: 2024-09-29 16:51:45

CodeForces 501D Misha and Permutations Summation的相关文章

501D Misha and Permutations Summation 数据结构+打脸题

都快退役啦,小白书上的例题还不会. 给出一个序列S,则S的字典序为 sigma(dp[i] * (n-i)!) (1 <= i <= n).dp[i] 表示[i,n]这一段S的子序列内比num[i]小的数字的个数. 对于两个序列A,B,(ord(A) + ord(B))%n!可以转化成 sigma( (A_dp[i] + B_dp[i] + (A_dp[i+1]+B_dp[i+1])/(n-i+1))%(n-i+1)  )( 1 <= i <= n ,可以认为dp[n+1] ==

Codeforces Round #285 (Div.1 B &amp; Div.2 D) Misha and Permutations Summation --二分+树状数组

题意:给出两个排列,求出每个排列在全排列的排行,相加,模上n!(全排列个数)得出一个数k,求出排行为k的排列. 解法:首先要得出定位方法,即知道某个排列是第几个排列.比如 (0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0). 拿排列(1,2,0)来说,首位是1,前面有cnt=1个小于1的没被用过的数(0),所以它的排行要加上(cnt=1)*2!,第二位为2,因为1已经放了,所以小于2的只有0了,即cnt=1个,所以,排

CF501D Misha and Permutations Summation(康托展开)

以前写康托展开都是直接O(n^2),碰到了一定要nlogn的,存个代码. #pragma warning(disable:4996) #include <iostream> #include <cstring> #include <string> #include <vector> #include <cstdio> #include <cmath> #include <algorithm> using namespace

codeforces A. Slightly Decreasing Permutations 题解

Permutation p is an ordered set of integers p1,??p2,??...,??pn, consisting of n distinct positive integers, each of them doesn't exceed n. We'll denote the i-th element of permutation p as pi. We'll call number n the size or the length of permutation

codeforces 340E Iahub and Permutations(错排or容斥)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Iahub and Permutations Iahub is so happy about inventing bubble sort graphs that he's staying all day long at the office and writing permutations. Iahubina is angry that she is no more import

codeforces#285--C - Misha and Forest(拓扑排序变形)

C - Misha and Forest Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Description Let's define a forest as a non-directed acyclic graph (also without loops and parallel edges). One day Misha played with the

Codeforces 832D - Misha, Grisha and Underground

832D - Misha, Grisha and Underground 思路:lca,求两个最短路的公共长度.公共长度公式为(d(a,b)+d(b,c)-d(a,c))/2. 代码: #include<bits/stdc++.h> using namespace std; #define ll long long #define ls rt<<1,l,m #define rs rt<<1|1,m+1,r const int INF=0x3f3f3f3f; const

CODEFORCES Rockethon 2015 B. Permutations

You are given a permutation p of numbers 1,?2,?-,?n. Let's define f(p) as the following sum: Find the lexicographically m-th permutation of length n in the set of permutations having the maximum possible value of f(p). Input The single line of input

Codeforces 501C Misha and Forest(bfs)

题目链接:http://codeforces.com/problemset/problem/501/C 题意: 思路: 代码: #include <iostream> #include <stdio.h> #include <cstring> #include <queue> #include <set> #include <cmath> #include <time.h> #include <cstdlib>