zoukankan      html  css  js  c++  java
  • 康拓展开

    康托展开

    P5367 【模板】康托展开

    ​ 康托展开是用来干这个的:求 (1sim N) 的一个给定全排列在所有 (1sim N) 全排列中的排名。

    ​ 公式就是这个(ans = 1 + displaystyle sum_{i = 1}^{n} A[i] * (n - i)!)

    (A[i])表示(i + 1 sim n)中的数字比(i)上的数字小的个数。

    ​ 为啥呢?可以这么理解,枚举到第(i)位了,那前(i - 1)位肯定一样,第(i)位上可以填的数就是之前没用过的,比(i)上的数字小的数,也就是(A[i]),那(i)位之后怎么填就都可以了,也就是((n - i)!)

    ​ 得用树状数组维护一下,不然会(TLE)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e6 + 5, mod = 998244353;
    int n, ans, fac, a[N], t[N];
    
    int lowbit(int x) { return x & -x; }
    
    void change(int x) { for(; x <= N - 5; x += lowbit(x)) t[x] ++; }
    
    int query(int x) { int res = 0; for(; x ; x -= lowbit(x)) res += t[x]; return res; }
    
    int main() {
    
        n = read(); fac = 1;
        for(int i = 1;i <= n; i++) a[i] = read();
        for(int i = n;i >= 1; i--) {
            int tmp = query(a[i]);
            ans = (ans + 1ll * tmp * fac % mod) % mod;
            fac = 1ll * fac * (n - i + 1) % mod;
            change(a[i]);
        }
        printf("%d", ans + 1);
    
        return 0;
    }
    

    逆康拓展开

    UVA11525 Permutation

    ​ 问题是一样的,就是反过来了,给你一个排名,让你求对应的排列。

    ​ 因为这个排名太大了,题目给了你所有的(A[i]),这就好办了。我们开一颗权值线段树,每次找其中的第(A[i])大值,并不断删点就好了。

    #include <bits/stdc++.h>
    
    #define ls(o) (o << 1)
    #define rs(o) (o << 1 | 1)
    #define mid ((l + r) >> 1)
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 5e4 + 5;
    int T, n, s;
    int t[N << 2];
    
    void build(int o, int l, int r) {
        if(l == r) { t[o] = 1; return ; }
        build(ls(o), l, mid); build(rs(o), mid + 1, r);
        t[o] = t[ls(o)] + t[rs(o)];
    }
    
    int query(int o, int l, int r, int k) {
        t[o] --; if(l == r) return l;
        if(t[ls(o)] < k) return query(rs(o), mid + 1, r, k - t[ls(o)]);
        return query(ls(o), l, mid, k);
    }
    
    int main() {
    
        T = read();
        while(T --> 0) {
            n = read(); build(1, 1, n);
            for(int i = 1;i <= n; i++) {
                s = read(); 
                if(i != n) printf("%d ", query(1, 1, n, s + 1));
                if(i == n) printf("%d
    ", query(1, 1, n, s + 1)); //坑点
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    Java对象序列化文件追加对象的问题,以及Java的读取多个对象的问题解决方法。
    解决chrome在docky上的图标模糊或不能锁定的问题
    获取表单中的输入内容、单选按钮、复选框的输入内容
    用idea写servlet文件
    get方法和post方法
    解决Only a type can be imported. com.mysql.jdbc.Connection resolves to a package的报错问题
    idea中如何配置tomcat
    JDBC中的PreparedStatement
    JDBC中的ResultSet
    JDBCl链接中Statement
  • 原文地址:https://www.cnblogs.com/czhui666/p/13726967.html
Copyright © 2011-2022 走看看