「PKUSC2018」真實排名(排列組合,數學)
阿新 • • 發佈:2019-01-11
前言
為什麼隨機跳題會跳到這種題目啊?
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; }