LOJ6432 [PKUSC2018] 真实排名 【组合数】

题目分析:

做三个指针然后预处理阶乘就行。

 

题目代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 102000;
 5 
 6 const int mod = 998244353;
 7 
 8 int n,k;
 9 struct node{
10     int data,num;
11 }a[maxn];
12 
13 int ans[maxn];
14 
15 int fac[maxn],inv[maxn];
16 
17 int fast_pow(int now,int pw){
18     if(pw == 1)return now;
19     int z = fast_pow(now,pw/2);
20     z = (1ll*z*z)%mod;
21     if(pw & 1) z = (1ll*z*now)%mod;
22     return z;
23 }
24 
25 void init(){
26     fac[0] = 1;
27     for(int i=1;i<=n;i++) fac[i] = (1ll*fac[i-1]*i) %mod;
28     inv[n] = fast_pow(fac[n],mod-2);
29     for(int i=n;i>=1;i--){
30     inv[i-1] = (1ll*inv[i]*i)%mod;
31     }
32 }
33 
34 int C(int alpha,int beta){
35     if(beta > alpha) return 0;
36     return (((1ll*fac[alpha]*inv[beta])%mod)*(inv[alpha-beta]))%mod;
37 }
38 
39 int cmp(node alpha,node beta){return alpha.data > beta.data;}
40 
41 void read(){
42     scanf("%d%d",&n,&k);
43     for(int i=1;i<=n;i++) {
44     scanf("%d",&a[i].data),a[i].num = i;
45     }
46     sort(a+1,a+n+1,cmp);
47 }
48 
49 void work(){                       
50     init();
51     int pts = 1,ok = 1;
52     while(pts <= n && a[pts].data*2 >= a[1].data) pts++;
53     for(int i=1;i<=n;i++){
54     int nxt = i; while(nxt+1<=n && a[nxt+1].data == a[i].data) nxt++;
55     while(pts <= n && a[pts].data*2 >= a[i].data) pts++;
56     int forw = n-(pts-nxt),res = C(forw,k);
57     for(int j=i;j<=nxt;j++) ans[a[j].num] += res;
58     while(ok <= nxt && a[ok].data >= a[nxt].data*2) ok++;
59     int newm = k-(nxt-ok+1);
60     if(newm >= 0){
61         forw = n-(nxt-ok+1),res = C(forw,newm);
62         for(int j=i;j<=nxt;j++) ans[a[j].num] += res,ans[a[j].num] %= mod;
63     }
64     i = nxt;
65     }
66     for(int i=1;i<=n;i++) if(a[i].data == 0) ans[a[i].num] = C(n,k);
67     for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
68 }
69 
70 int main(){
71     read();
72     work();
73     return 0;
74 }

 

posted @ 2018-06-11 16:02  menhera  阅读(161)  评论(0编辑  收藏  举报