LOJ#6432. 「PKUSC2018」真实排名 组合
这题怕不是 sb 题吧,随便分类讨论一下 $i$ 乘不乘 2 倍就没了.
然后细节要注意一下:题中要求的是大于等于.
求值域在 $[L,R]$ 中的元素个数时我用的权值线段树,可能会比二分要慢一点,但是不用判边界.
code:
#include <bits/stdc++.h> #define ll long long #define N 100009 #define lson s[x].ls #define rson s[x].rs #define inf 2000000000 #define mod 998244353 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int tot; int a[N],fac[N],inv[N],b[N]; struct data { int sum,ls,rs; }s[N*30]; int qpow(int x,int y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } int INV(int x) { return qpow(x,mod-2); } void init() { fac[0]=inv[0]=1; for(int i=1;i<N;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=INV(fac[i]); } int query(int x,int l,int r,int L,int R) { if(!x) return 0; if(l>=L&&r<=R) return s[x].sum; int mid=(l+r)>>1,re=0; if(L<=mid) re+=query(lson,l,mid,L,R); if(R>mid) re+=query(rson,mid+1,r,L,R); return re; } void update(int &x,int l,int r,int p,int v) { if(!x) x=++tot; s[x].sum+=v; if(l==r) return; int mid=(l+r)>>1; if(p<=mid) update(lson,l,mid,p,v); else update(rson,mid+1,r,p,v); } int C(int x,int y) { if(x<0||y<0||x<y) return 0; return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; } int main() { // setIO("input"); // freopen("input.out","w",stdout); int n,k,rt=0,x,y,z; init(); scanf("%d%d",&n,&k); for(int i=1;i<=n;++i) scanf("%d",&a[i]),update(rt,0,inf,a[i],1),b[i]=a[i]; for(int i=1;i<=n;++i) { if(a[i]==0) printf("%d\n",C(n,k)); else { x=(a[i]&1)?a[i]/2:(a[i]/2)-1; int SUM=query(rt,0,inf,0,x)+query(rt,0,inf,a[i],inf)-1; int ANS=C(SUM,k); update(rt,0,inf,a[i],-1); int sum2=query(rt,0,inf,a[i],inf); int sum1=query(rt,0,inf,2*a[i],inf); // 还缺 sum2-sum1 int to=query(rt,0,inf,a[i],2*a[i]-1); (ANS+=C(to,sum2-sum1)*C(n-to-1,k-sum2+sum1-1)%mod)%=mod; printf("%d\n",ANS); update(rt,0,inf,a[i],1); } } return 0; }