zoukankan      html  css  js  c++  java
  • 【AtCoder】CODE FESTIVAL 2016 qual C E-順列辞書 / Encyclopedia of Permutations

    下文所有$s_i$均表示序列上第i位的数字

    考虑对于一个位置的值$s_i$有什么东西能统计进去

    考虑统计恰好在$i$这个这个位置分出大小的元素

    发现对于一个$s_i$,答案是$sum(s_i - 1 -sum_{j=1}^{i-1}[s_j<s_i])*(N-i)!$

    发现后面这个东西是统一乘的,于是只考虑前半部分

    接下来对当前这个$s_i$的位置分类讨论

    然后我们可以发现前半部分又可以拆成两个部分

    $sum s_i$ 和 $sum_{j=1}^{i-1}[s_j<s_i]$

    为了方便表达,接下来定义空的位置为$K$,未被填入的数字减一的和为$s$ 大于$s_i$的数的和为$Sum_i$

    于是我们现在就要计算的是有多少合法的比它小的排列 和 其中$s_j<s_i$的个数

    对于前面那个东西 分类

    ① 如果$s_i$不为空的话,那么$ans=(s_i - 1)*K!$

    ② 如果$s_i$为空的话 那么答案就是 $s * (K-1)!$[考虑每个数字填入 然后根据①中的式子合并一下==]

    然后接下来就统计的是$s_j<s_i$的对数

    还是分类 对于$s_j$ 和 $s_i$是否有取值分开讨论 2*2=4种

    $(I)$

    当$i$为空时

    ①$j$不为空

    考虑空位中大于$j$位置上数的方案数,这个可以前缀统计一下,对于每个存在的$s_j$,$pre+=Sum_{s_j}*(K-1)!$[考虑空位中比它大的个数 其余随便填入]

    ②$j$为空

    记前面的空位数量为$cnt$

    等价于在$K$个数里选两个,剩下任意填入

    即$cnt*C_{K}^{2}*(K-2)!$

    $(II)$

    当$i$不为空时

    ①如果$j$不为空

    直接用树状数组维护小于$s_i$的值的个数==

    ②如果$j$为空

    在没有填的数字里面选一个比$s_i$小的数填进去就完事了……

    这个直接$cnt*(Sum_1-Sum_{s_i})*(K-1)!$

    然后就做完了x

     #include <bits/stdc++.h>
    using namespace std;
    const long long fish=1e9+7;
    const int mx=300000;
    bool pd[300005];
    int p[300005],N,K;
    long long fac[300005],inv[300005],Sum[300005],ans[300005],Tree[300005];
    long long Pow(long long x,int y){
        long long ans=1;
        for (;y;y>>=1,x=1ll*x*x%fish) if (y&1) ans=1ll*ans*x%fish;
        return ans; 
    }
    int Lowbit(int x){ return (x&(-x));}
    void Insert(int x,int y){for (int j=x;j<=mx;j+=Lowbit(j)) Tree[j]+=y;}
    long long query(int x) {long long ans=0;for (int i=x;i;i-=Lowbit(i)) ans+=Tree[i];return ans;}
    long long  C(int n,int r){
        if (n<r) return 0;
        return 1ll*fac[n]*inv[r]%fish*1ll*inv[n-r]%fish;
    }
    void Pre(){
        scanf("%d",&N);
        fac[0]=1;
        for (int i=1;i<=N;i++)
            fac[i]=1ll*fac[i-1]*i%fish;
        inv[N]=Pow(fac[N],fish-2);
        for (int i=N-1;i>=0;i--)
            inv[i]=1ll*inv[i+1]*(i+1)%fish;
        for (int i=1;i<=N;i++){
            scanf("%d",&p[i]);
            if (p[i]) pd[p[i]]=true;
            else ++K;
        }
    }
    void Work(){
        long long ss=0;
        for (int i=N;i>=1;i--){
            Sum[i]+=Sum[i+1];
            if (!pd[i]){
                Sum[i]++;
                (ss+=(i-1))%=fish;
            }
        }
        long long Pre=0,Rem=0;
        for (int i=1;i<=N;i++){
        
            if (!p[i]) {
                ans[i]=(ans[i]-Pre+fish)%fish;
                (ans[i]+=1ll*ss*fac[K-1]%fish)%=fish;            
                if (K>=2) ((ans[i]-=1ll*Rem*C(K,2)%fish*fac[K-2]%fish)+=fish)%=fish;
                //cout<<C(K,2)<<endl;
                Rem++;
            }
            else{
                (ans[i]+=1ll*(p[i]-1)*fac[K])%=fish;
                ans[i]=((ans[i]-(1ll*query(p[i]-1)*1ll*fac[K])%fish)+fish)%fish;
                if (K) ((ans[i]-=Rem*(Sum[1]-Sum[p[i]])%fish*fac[K-1]%fish)+=fish)%=fish;
                if (K) (Pre+=1ll*Sum[p[i]+1]*fac[K-1]%fish)%=fish;
                Insert(p[i],1);
            }
        }
        long long Ans=fac[K];
        for (int i=1;i<=N;i++){    
            //cout<<ans[i]<<" "<<i<<endl;
            Ans=(Ans+1ll*fac[N-i]*ans[i]%fish)%fish;
            //cout<<i<<" "<<ans[i]<<endl;
        }
        cout<<(Ans+fish)%fish;
        return;
    }
    int main(){
        Pre();
        Work();
        return 0;
    }
  • 相关阅读:
    前端开发 vue,angular,react框架对比1
    前端开发 Angular
    前端开发 Vue Vue.js和Node.js的关系
    net技术
    net技术方案
    软件工程项目费用计算
    前端开发 Vue -4promise解读2
    前端开发 Vue -4promise解读1
    mybatis与hibernate区别
    struts2和springmvc的区别
  • 原文地址:https://www.cnblogs.com/si--nian/p/11784082.html
Copyright © 2011-2022 走看看