• Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations


    题意:

    对于一个长度为n的排列P,如果P在所有长度为n的排列中,按照字典序排列后,在第s位,则P的value为s

    现在给出一个长度为n的排列P,P有一些位置确定了,另外一些位置为0,表示不确定。

    现在问,P的所有可能的排列的value之和

    n <= 500000

    思路:

    对于一个可能的排列,它的value为所有小于它的排列的个数 + 1反过来,对于一个排列a,如果P的可能的排列中有sum个排列大于a,则a对答案的贡献为sum

    那我们就可以枚举位数,

    一位一位的考虑:

    对于2个排列P,b,我们假设它在第i位分出大小,即[1,i-1]的位置2个排列相同,并且第i位有P[i]  > b[i]

    并且P就是满足条件的可能的排列,那我们算出这个时候有x个可能的P,y个可能的b,则对答案的贡献

    为x * y

    为了方便,我们从后面往前面枚举

    那对于位数i,我们只需要分2 * 2种情况考虑:

    自由的数表示没有被固定位置的数

    suf表示i后面有多少个没有被确定的位置

    sum表示P一共有多少个没有被确定的位置

    1. Pi的位置确定了

    1.1 b在i处放的数为[1,P[i]-1]中被固定在[i+1,n]中某一位的数,设有x个,则贡献:

       x * sum! * (n - i)!

      求x的话用一个树状数组bit记录就可以了,遇见固定的数就扔进bit里面

    1.2   b在i处放的数为[1,P[i]-1]中自由的数,设有y个,则贡献:

      y * suf * (sum - 1)! * (n - i)!

      提前把所有自由的数放到一个树状数组bit2中,就可以快速得到y了

    2 P[i]处的数没有确定

    2.1 b在i处放的数也是自由的数,则贡献:

      C(sum,2) * (sum - 2)! * suf * (n - i)!

    2.2 b在i处放的数是[1,P[i]-1]中被固定在i后面某一位的数

      假设P[i]放的是x,则b[i]放的应该是[1,x-1]中被固定在i后面的数,设[1,x-1]中被固定在i后面的数

      有y个,则贡献:

      y * (sum - 1)! * (n - i)!

      所以这部分的贡献需要我们枚举x,对于每一个x求有多少个y?

      不用,用线段树可以维护,总贡献为:

      seg[1].s * (sum - 1)! * (n - i)!

    所以这道题目就搞定了,接下来说说线段树维护的是什么

    Seg{int n;int ly;LL s}

    线段树只需要维护自由的那一些数,因为枚举的x是自由的数

    对于叶子节点i

    s表示表示目前被固定的数中,比i小的有多少个

    n表示这个叶子节点是不是自由的数

    则对于所有节点:

    n表示这个区间有多少个自由的数

    s表示这个区间的自由的数的s之和

    代码:

                                                
      //File Name: E.cpp
      //Author: long
      //Mail: 736726758@qq.com
      //Created Time: 2016年10月26日 星期三 10时29分59秒
                                       
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <set>
    #include <math.h>
    #include <vector>
    #define LL long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const int MAXN  = 500000 + 5;
    const int MOD = (int)1e9 + 7;
    int p[MAXN],bit1[MAXN],bit2[MAXN],n;
    bool use[MAXN];
    LL jie[MAXN];
    void update(int x,int add,int *bit){
        for(int i=x;i<=n;i+=i&-i)
            bit[i] += add;
    }
    int query(int x,int *bit){
        int res = 0;
        for(int i=x;i>0;i-=i&-i)
            res += bit[i];
        return res;
    }
    struct Seg{
        int n,ly;
        LL s;
    }seg[MAXN << 2];
    void pushup(int rt){
        seg[rt].s = seg[rt<<1].s + seg[rt<<1|1].s;
        seg[rt].n = seg[rt<<1].n + seg[rt<<1|1].n;
    }
    void pushdown(int rt){
        if(seg[rt].ly){
            int &ly = seg[rt].ly;
            int L = rt<<1,R = rt<<1|1;
            seg[L].ly += ly,seg[R].ly += ly;
            seg[L].s += (LL)seg[L].n * ly;
            seg[R].s += (LL)seg[R].n * ly;
            ly = 0;
        }
    }
    void build(int l,int r,int rt){
        seg[rt].s = seg[rt].ly = seg[rt].n = 0;
        if(l == r){
            if(!use[l]) seg[rt].n = 1;
            return ;
        }
        int m = l + r >> 1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    void update(int L,int R,int add,int l,int r,int rt){
        if(L <= l && R >= r){
            seg[rt].ly += add;
            seg[rt].s += (LL)add * seg[rt].n;
            return ;
        }
        pushdown(rt);
        int m = l + r >> 1;
        if(L <= m) update(L,R,add,lson);
        if(R > m) update(L,R,add,rson);
        pushup(rt);
    }
    int init(){
        build(1,n,1);
        jie[0] = 1;
        for(int i=1;i<=n;i++)
            jie[i] = jie[i-1] * i % MOD;
        int sum = 0;
        for(int i=1;i<=n;i++){
            if(!use[i]){
                update(i,1,bit2);
                sum++;
            }
        }
        return sum;
    }
    LL solve(){
        int sum = init();
        LL ans = 0,tmp1,tmp2;
        int suf = 0;
        for(int i=n;i>0;i--){
            tmp1 = tmp2 = 0;
    //        ans = 0;
            if(p[i]){
                int x = query(p[i] - 1,bit1);
                tmp1 = x * jie[sum] % MOD * jie[n - i] % MOD;
                int y = query(p[i],bit2);
                if(sum >= 1)
                    tmp2 = (LL)y*suf % MOD * jie[sum-1] % MOD * jie[n-i] % MOD;
                ans = (ans + tmp1 + tmp2) % MOD;
                update(p[i],1,bit1);
                if(p[i] < n) update(p[i]+1,n,1,1,n,1);
            }
            else{
                if(sum >= 2)
                    tmp1 = ((LL)sum * (sum - 1) / 2) % MOD * jie[sum-2] % MOD * suf % MOD * jie[n-i] % MOD;
                if(sum >= 1)
                    tmp2 = seg[1].s % MOD * jie[sum-1] % MOD * jie[n-i] % MOD;
    //            printf("tmp1 = %lld
    tmp2 = %lld
    ",tmp1,tmp2);
                ans = (ans + tmp1 + tmp2) % MOD;
                suf++;
            }
    //        printf("i = %d ans = %lld
    ",i,ans);
        }
    //    cout << jie[sum] << endl;
        ans = (ans + jie[sum]) % MOD;
        return ans;
    }
    int main(){
        scanf("%d",&n);
        memset(use,false,sizeof(use));
        for(int i=1;i<=n;i++){
            scanf("%d",p + i);
            use[p[i]] = true;
        }
        printf("%d
    ",(int)solve());
        return 0;
    }
    View Code
  • 相关阅读:
    <span>和<div>标签的隐藏和显示切换
    重启svn
    Mac下配置apache
    iOS时间显示今天昨天
    关于UIPageViewController那些事
    关于plist文件的那些事
    Xcode调试LLDB
    Reveal安装
    静态初始化器
    Static简介
  • 原文地址:https://www.cnblogs.com/-maybe/p/6000257.html
Copyright © 2020-2023  润新知