题目链接

https://loj.ac/problem/6432

思路

如果第i个选手的分数没有变,那么要维持这个选手的排名,分数为[vi2,vi)的选手分数都不能变,设c=cnt[vi2,vi),那么方案数就是

(nc1k)

如果第i个选手的分数变了,那么要维持这个选手的排名,分数为[vi,2vi)的选手分数都要变,设c=cnt[vi,2vi),那么方案数为

(nckc)

统计值在区间[l,r)内的个数:若rk为权值排好序后的结果,那么答案就是std::lower_bound(rk+1,rk+n+1,r)-std::lower_bound(rk+1,rk+n+1,l)

代码

#include <cstdio>
#include <algorithm>

const int maxn=100000;
const int mo=998244353;

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

int n,k,v[maxn+10],fac[maxn+10],ifac[maxn+10],rk[maxn+10];

inline int c(int a,int b)
{
  if((a<0)||(b<0)||(a<b))
    {
      return 0;
    }
  return 1ll*fac[a]*ifac[b]%mo*ifac[a-b]%mo;
}

inline int get(int l,int r)
{
  if(l>=r)
    {
      return 0;
    }
  return std::lower_bound(rk+1,rk+n+1,r)
    -std::lower_bound(rk+1,rk+n+1,l);
}

int main()
{
  n=read();
  k=read();
  for(int i=1; i<=n; ++i)
    {
      v[i]=rk[i]=read();
    }
  std::sort(rk+1,rk+n+1);
  fac[0]=1;
  for(int i=1; i<=n; ++i)
    {
      fac[i]=1ll*fac[i-1]*i%mo;
    }
  ifac[0]=ifac[1]=1;
  for(int i=2; i<=n; ++i)
    {
      ifac[i]=1ll*(mo-mo/i)*ifac[mo%i]%mo;
    }
  for(int i=1; i<=n; ++i)
    {
      ifac[i]=1ll*ifac[i-1]*ifac[i]%mo;
    }
  for(int i=1; i<=n; ++i)
    {
      if(v[i])
        {
          int ans=0,cnt=get((v[i]+1)>>1,v[i]);
          ans+=c(n-cnt-1,k);
          cnt=get(v[i],v[i]<<1);
          ans+=c(n-cnt,k-cnt);
          printf("%d\n",ans%mo);
        }
      else
        {
          printf("%d\n",c(n,k));
        }
    }
  return 0;
}