CF938E-組合數

yoshinow2001發表於2024-03-21

link:https://codeforces.com/contest/938/problem/E
題意:給一個序列 \(a\) ,按如下方式計算 \(f_a\)

  • 初始 \(f_a=0,M=1\)
  • 對每個 \(2\leq i\leq n\),如果 \(a_M<a_i\)\(f_a\to f_a+a_M\),然後 \(M=i\)
    對所有 \(a\) 的排列計算 \(f_a\) 並其在模 \(10^9+7\) 下的和。
    \(1\leq n\leq 10^6,1\leq a_i\leq 10^9\)

對每個序列的 \(f_a\) 的值是一段從 \(a_1\) 開始的上升序列的和,並且 \(a\) 的最大值沒有貢獻,反過來考慮每個 \(a_i<\max(a)\) 的貢獻:

  • \(a_i\) 在位置 \(j\) 處出現,要產生貢獻當且僅當前面的數嚴格比 \(a_i\) 小,假設這樣的數有 \(s_i\) 個,則有 \(s_i!/(s_i-(j-1))!\) 种放法,後面的數隨便放,有 \((n-j)!\) 種,$$\sum_{j=1}^n \frac{s_i!(n-j)!}{(s_i-j+1)!}=s_i!\sum_{j=1}^n \frac{(n-j)!}{(s_i-j+1)!}\frac{(n-1-s_i)!}{(n-1-s_i)!}=s_i!(n-1-s_i)! \sum_{j=1}^n \binom{n-j}{n-1-s_i}$$經典上指標求和,翻轉指標,從\(\binom{n}{k}=\binom{n-1}{k}+\binom{n-1}{k-1}\)\(\binom{n}{-1}=0\),為 可以倒推:$$s_i!(n-1-s_i)!\sum_{j=0}^{n-1}\binom{j}{n-1-s_i}=s_i!(n-1-s_i)!\binom{n}{n-s_i}$$
  • 對每個值計算貢獻即可
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int N=1e6+55;
const int MOD=1e9+7;
int ksm(int a,int b){
    int ret=1;a%=MOD;
    for(;b;b>>=1,a=(ll)a*a%MOD)if(b&1)ret=(ll)ret*a%MOD;
    return ret;
}
int n,a[N],fact[N],inv_fact[N];
map<int,int> S;
int C(int n,int k){
    if(k>n)return 0;
    return (ll)fact[n]*inv_fact[k]%MOD*inv_fact[n-k]%MOD;
}
int main(){
    fastio;
    fact[0]=1;
    rep(i,1,N-5)fact[i]=(ll)fact[i-1]*i%MOD;
    inv_fact[N-5]=ksm(fact[N-5],MOD-2);
    for(int i=N-5;i>=1;i--)inv_fact[i-1]=(ll)inv_fact[i]*i%MOD;
    cin>>n;
    int mx=0;
    rep(i,1,n){
        cin>>a[i];
        S[a[i]]++;
        mx=max(mx,a[i]);
    }
    int cnt=0,ans=0;
    for(auto [x,c]:S)if(x!=mx){
        ans=(ans+(ll)x*fact[cnt]%MOD*fact[n-cnt-1]%MOD*C(n,n-cnt)%MOD*c%MOD)%MOD;
        cnt+=c;
    }
    cout<<ans;
    return 0;
}

相關文章