[LOJ 6432][PKUSC 2018]真實排名

[LOJ 6432][PKUSC 2018]真實排名

題意

給定 \(n\) 個選手的成績, 選中其中 \(k\) 個使他們的成績翻倍. 對於每一個選手回答有多少種方案使得他的排名不發生變化.c++

\(n\le 10^5\)git

題解

場上惟一A掉的題?spa

分兩類討論, 一類是當前選手翻倍了, 一類是不加倍.code

  • 若是當前選手不加倍, 那麼全部加倍後會超過當前選手的選手都不能加倍, 其餘人隨意. 方案數量顯然就是在剩下的人中選 \(k\) 個的方案數量。
  • 若是當前選手加倍, 那麼全部加倍後被超過的選手也必須加倍, 其餘人隨意. 方案數也是個組合數.

因而這沙雕題就作完了. 場上只A這一題的我可真是個沙雕.blog

參考代碼

#include <bits/stdc++.h>

const int MAXN=1e5+10;
const int MOD=998244353;

int n;
int k;
int a[MAXN];
int s[MAXN];
int h[MAXN];
int d[MAXN];
int inv[MAXN];
int fact[MAXN];

int ReadInt();
int C(int,int);
int Pow(int,int,int);

int main(){
    n=ReadInt();
    k=ReadInt();
    for(int i=1;i<=n;i++)
        s[i]=a[i]=ReadInt();
    std::sort(s+1,s+n+1);
    fact[0]=1;
    for(int i=1;i<=n;i++)
        fact[i]=1ll*fact[i-1]*i%MOD;
    inv[n]=Pow(fact[n],MOD-2,MOD);
    for(int i=n;i>=1;i--)
        inv[i-1]=1ll*inv[i]*i%MOD;
    for(int i=1;i<=n;i++){
        if(a[i]==0)
            printf("%d\n",C(n,k));
        else{
            int ans=0;
            int d=std::lower_bound(s+1,s+n+1,a[i])-std::lower_bound(s+1,s+n+1,(a[i]+1)/2);
            (ans+=C(n-d-1,k))%=MOD;
            d=std::lower_bound(s+1,s+n+1,a[i]*2)-std::lower_bound(s+1,s+n+1,a[i]);
            (ans+=C(n-d,k-d))%=MOD;
            printf("%d\n",ans);
        }
    }
    return 0;
}

int C(int n,int m){
    return n<m||n<0||m<0?0:1ll*fact[n]*inv[m]%MOD*inv[n-m]%MOD;
}

int Pow(int a,int n,int p){
    int ans=1;
    while(n>0){
        if(n&1)
            ans=1ll*a*ans%p;
        a=1ll*a*a%p;
        n>>=1;
    }
    return ans;
}

inline int ReadInt(){
    int x=0;
    register char ch=getchar();
    while(!isdigit(ch))
        ch=getchar();
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}

相關文章
相關標籤/搜索