码迷,mamicode.com
首页 > 其他好文 > 详细

【AtCoder】CODE FESTIVAL 2016 qual C E-順列辞書 / Encyclopedia of Permutations

时间:2019-11-02 21:48:11      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:int   维护   mes   code   部分   end   turn   color   统一   

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

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

发现对于一个$s_i$,答案是$(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$为空

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

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

$(II)$

当$i$不为空时

①如果$j$不为空

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

②如果$j$为空

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

这个直接$(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;
}

 

【AtCoder】CODE FESTIVAL 2016 qual C E-順列辞書 / Encyclopedia of Permutations

标签:int   维护   mes   code   部分   end   turn   color   统一   

原文地址:https://www.cnblogs.com/si--nian/p/11784082.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!