【LOJ】#6432. 「PKUSC2018」真实排名

题解

一道水题。。。
分别考虑当前点自己翻和不翻的情况。
一波组合数。
注意线性求完逆元后记得求前缀啊…(调了半个小时才发现没求前缀(捂脸


代码

#include<cstdio>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e5+10,mod=998244353;
typedef long long ll;
int n,Q,a[N],b[N],rk[N];
int ls[N][2],mr[N][2],si;
ll r[N],inv[N],ans;

inline int rd()
{
    register char ch=getchar();register int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

inline bool cmp(const int&x,const int&y){return a[x]<a[y];}
inline ll C(int n,int m){return r[n]*inv[m]%mod*inv[n-m]%mod;}

int main(){
    register int i,j,pos,k,inc;
    n=rd();Q=rd();r[1]=1;r[0]=1;inv[1]=1;inv[0]=1;
    for(i=2;i<=n;++i)r[i]=1ll*r[i-1]*i%mod,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(i=2;i<=n;++i) inv[i]=inv[i]*inv[i-1]%mod; ///记得求前缀和啊,不要线性推完逆元就跑了QWQ 
    for(i=1;i<=n;++i){a[i]=rd();b[i]=i;}
    sort(b+1,b+n+1,cmp);
    for(pos=0,k=0,i=2;i<=n;++i){
        for(;a[b[pos+1]]*2<a[b[i]] && pos<i-1;++pos);
        for(;a[b[k+1]]<a[b[i]] && k<i-1;++k);
        ls[b[i]][0]=pos;ls[b[i]][1]=k-pos;
    }
    for(pos=n+1,k=n+1,i=n-1;i>=1;--i){
        for(;a[b[pos-1]]>=a[b[i]]*2 && pos>i+1;--pos);
        for(;a[b[k-1]]>a[b[i]] && k>i+1;--k);
        mr[b[i]][0]=pos-k;mr[b[i]][1]=n-pos+1;
    }
    for(i=1;i<=n;++i){
        if(a[i]==0){printf("%lld\n",C(n,Q));continue;}
        ans=0;
        si=n-(ls[i][0]+ls[i][1]+mr[i][0]+mr[i][1]);
        k=ls[i][0]+si+mr[i][1]+mr[i][0]-1;
        if(Q<=k) ans+=C(k,Q);
        k=si+mr[i][0];
        if(Q>=k && Q-k<=n-k) ans=(ans+C(n-k,Q-k))%mod;
        printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值