• [JZOJ5772]【NOIP2008模拟】今天你AK了吗?


    Description

    AK:All kill
    “你为什么没背书?”
    “没有为什么,我就是没背书。”
    “……我去年买了个表,G—U—N!”
    头铁王InFleaKing把背书的时间都拿去列排列了......
    n=3的排列一共有六个(顺序按字典序从小到大):
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1
    气不打一处来的InFleaKing把n的排列打乱了。
    他想知道字典序第k小的n的排列是什么?
    由于InFleaKing被捉去背书了,所以这个问题只能交给被万人顶礼膜拜的dalao您来解决了。
     

    Input

    一行,两个数,分别是n,k。
    n,k的含义见题目描述。

    Output

    一行,n个数。
    代表字典序第k小的n的排列。
    注意两两数之间要用空格隔开。
     

    Sample Input

    Sample Input1:
    1 1
    
    Sample Input2:
    2 2
     

    Sample Output

    Sample Output1:
    1
    
    Sample Output2:
    2 1
     
     

    Data Constraint

    【数据约定】
    对于10%的数据:1<=n<=3
    对于20%的数据,1<=n<=9
    对于30%的数据:1<=n<=18,1<=k<=10^6
    对于60%的数据:1<=n<=18
    对于80%的数据:1<=n<=100,1<=k<=10^100
    对于90%的数据:1<=n<=1000,1<=k<=10^1000
    对于100%的数据:1<=n<=100000,1<=k<=min(10^20000,n!)

    直接模拟...不知道为什么讲的这么玄学。

    其实是显然的事。

    对于从左到右的位置i,前面有(n-1)!种可能...

    于是就把剩下的数字中第k / (n - 1)!个数选到当前位置, 然后k %= (n - 1)!,

    然后对于后面也是这样。。。

    要写高精不开心,直接弃疗,手懒,我是不会写高精的233.

    复杂度是O(N^2)的过不去,听讲解的什么奇怪算法不太明白为什么要这么做。

    直接用树状数组维护, 再套二分找第k个数就ok了。

    复杂度O(Nlog^2N)。

    考场上O(N^2)能过不写高精的数据,于是弃疗了没写树状数组套二分。

    放上考场60分代码


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <vector>
    #include <algorithm>
    using namespace std;
    inline int read() {
        int res=0;char c=getchar();bool f=0;
        while(!isdigit(c)) {if(c=='-')f=1;c=getchar();}
        while(isdigit(c))res=(res<<3)+(res<<1)+(c^48),c=getchar();
        return f?-res:res;
    }
    #define ll long long 
    int n;
    unsigned ll k;
    int wei[200005];
    unsigned ll fac[1000005];
    bool vis[1000005];
    
    int main()
    {
        freopen("array.in", "r", stdin);
        freopen("array.out", "w", stdout);
        n = read();
        fac[1] = 1;
        for (int i = 2 ; i <= n ; i ++) fac[i] = fac[i-1] * i;
        cin >> k;
        k--;
        for (register int i = 1 ; i < n ; i ++) 
        {
            int re,sum = 0;
            for (register int j = 1 ; j <= n; j ++) 
            {
                if (sum == k / fac[n-i] + 1) break;
                if (!vis[j]) re = j, sum++;
            }
            printf("%d ", re);
            vis[re] = 1;
            k %= fac[n-i];
        }
        for (register int i = 1 ; i <= n ; i ++) if (!vis[i]) return printf("%d", i), 0;
        return 0;
    }
  • 相关阅读:
    团队冲刺二(6)
    团队冲刺二(5)
    JAVA面试中问及HIBERNATE与 MYBATIS的对比,在这里做一下总结
    解决ADB server didn't ACK问题,连上手机问题
    ADB server didn't ACK
    android错误
    Andy
    在Eclipse下搭建Android开发环境教程
    VM VirtualBox 安装 Android 4.3虚拟机完整教程
    电脑安装Android4.0虚拟机的做法
  • 原文地址:https://www.cnblogs.com/BriMon/p/9443353.html
Copyright © 2020-2023  润新知