1. 程式人生 > >「PKUSC2018」真實排名(排列組合,數學)

「PKUSC2018」真實排名(排列組合,數學)

前言

為什麼隨機跳題會跳到這種題目啊?

Solution

我們發現可以把這個東西分情況討論:
1.這個點沒有加倍

  • 這一段相同的可以看成一個點,然後後面的都可以。
  • 這一段看成一個點,然後前面的不能對他造成影響的都可以。

2.這個點加倍了

  • 這一段相同的看做一個點,然後前面的都可以
  • 這一段相同的看成一個點,然後後面的如果對他的排名有影響,一定要加倍。

剩下的用組合數隨便亂算一下就好了。

程式碼實現

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi(){
    int f=1,sum=0;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int N=100010,Mod=998244353;
struct node{int id,val;};
bool cmp(node a,node b){return a.val<b.val;}
node a[N];
int jc[N],jcn[N],inv[N],n,k,ans[N],pre[N],last;
int C(int n,int m){
    if(n<0 || m<0 || n<m)return 0;
    return (ll)jc[n]*jcn[m]%Mod*jcn[n-m]%Mod;
}
void init(){
    jc[0]=jcn[0]=inv[1]=1;
    for(int i=1;i<=n;i++)jc[i]=(ll)jc[i-1]*i%Mod;
    for(int i=2;i<=n;i++)inv[i]=(ll)(Mod-Mod/i)*inv[Mod%i]%Mod;
    for(int i=1;i<=n;i++)jcn[i]=(ll)jcn[i-1]*inv[i]%Mod;
}
int main(){
    n=gi();k=gi();
    for(int i=1;i<=n;i++)a[i].val=gi(),a[i].id=i;
    init();
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(a[last].val!=a[i].val)last=i;
        pre[i]=last;
    }
    for(int i=1;i<=n;i++){
        int tmp=i;
        int now=a[tmp].id,have;i=pre[i];
        have=n-i;
        int l=1,r=i-1,wh=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(a[mid].val*2>=a[i].val){wh=mid;r=mid-1;}
            else l=mid+1;
        }
        have+=i-1;
        if(wh)have-=i-wh;
        ans[now]=C(have,k);
        have=i-1;int K=k-1;
        l=1,r=n;wh=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(a[mid].val<a[i].val*2){wh=mid;l=mid+1;}
            else r=mid-1;
        }
        if(!wh)have+=n-i;
        else{K=K-wh+i;have+=n-wh;}
        ans[now]=(ans[now]+C(have,K))%Mod;
        i=tmp;
    }
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
    return 0;
}