【BZOJ5368/Pkusc2018】真实排名

                               5368: [Pkusc2018]真实排名

                                            Time Limit: 10 Sec  Memory Limit: 256 MB
                                                             Submit: 163  Solved: 83

Description

小C是某知名比赛的组织者,该比赛一共有n名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排名是

:成绩不小于他的选手的数量(包括他自己)。例如如果333位选手的成绩分别是[1,2,2],那么他们的排名分别是

[3,2,2]。拥有上帝视角的你知道所有选手的实力,所以在考试前就精准地估计了每个人的成绩,设你估计的第iii

个选手的成绩为Ai,且由于你是上帝视角,所以如果不发生任何意外的话,你估计的成绩就是选手的最终成绩。但

是在比赛当天发生了不可抗的事故(例如遭受到了外星人的攻击),导致有一些选手的成绩变成了最终成绩的两倍

,即便是有上帝视角的你也不知道具体是哪些选手的成绩翻倍了,唯一知道的信息是这样的选手恰好有k个。现在

你需要计算,经过了不可抗事故后,对于第i位选手,有多少种情况满足他的排名没有改变。由于答案可能过大,

所以你只需要输出答案对998244353取模的值即可。

Input

第一行两个正整数n,k

第二行n个非负整数A1..An

1≤k<n≤10^5 ,0≤Ai≤10^9

Output

输出n行,第i行一个非负整数ansi,表示经过不可抗事故后,第i位选手的排名没有发生改变的情况数。

Sample Input

3 2
1 2 3

Sample Output

3
1
2
样例解释
一共有3种情况:(1,2)翻倍,(1,3)翻倍,(2,3)翻倍。
对于第一个选手来说,他的成绩就算翻倍,其他人都不低于他,所以任意情况下他的排名都不会改变。
对于第二个选手来说,如果是(1,2)翻倍,成绩变成(2,4,3),他的排名变成了第一;
如果是(1,3)翻倍,则成绩变成(2,2,6),他的排名变成了第三;如果是(2,3)翻倍,则成绩变成(1,4,6),他的排名还是第二。
所以只有一种情况。
对于第三个选手来说,如果是(1,2)翻倍,他的排名会变成第二,其他情况下都还是第一。

 

解析:

       求出每个人的排名rank然后分这个人是否乘2进行讨论,设这个人的分数为w。

       每次求出 原来小于w,乘2后也小于w的个数sum1.原来大于等于w,乘2后也大于等于w的个数sum2,其他的人数sum3。设第三种人选了q个人。如果有p3+q=rank-1。那么答案为C(p2)(q)*C(p1+p3)(K-q2)或C(p2)(q)*C(p1+p3)(K-q-1)。

       注意当a[i]=0时直接令答案为C(n)(K)即可,省的在求p3的时候特判。细节见代码。

 

代码(不太优秀QWQ):

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int Max=100010;
const int mod=998244353;
int n,m,k,sum1,sum2,sum3,q;
int num[Max],a[Max],b[Max],ans[Max],mul[Max],rank[Max],inv[Max];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-'){f=-1;c=getchar();}
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
inline void print(int x)
{
	if(x>9) print(x/10);
	putchar('0'+x%10);
}

inline int ksm(int a,int b)
{
	int ans=1;
	while(b)
	{
	  if(b&1) ans=((LL)(ans)*(LL)(a))%mod;
	  b>>=1;
	  a=((LL)(a)*(LL)(a))%mod;
	}
	return ans;
}

inline void pre()
{
	mul[1]=mul[0]=1;
	for(int i=2;i<=n;i++) mul[i]=((LL)(mul[i-1])*(LL)(i))%mod;
	inv[1]=inv[0]=1;
	for(int i=2;i<=n;i++) inv[i]=ksm(mul[i],mod-2);
}

inline int C(int n,int m)
{
	if(n>=0 && m>=0 && n>=m) return ((LL)(mul[n])*(LL)(inv[m])%mod*(LL)(inv[n-m])%mod)%mod;
	return 0;
}

int main()
{
	n=get_int(),k=get_int();
	pre();
	for(int i=1;i<=n;i++) num[i]=a[i]=get_int(),b[i]=a[i]<<1;
	sort(a+1,a+n+1),sort(b+1,b+n+1);
	for(int i=1;i<=n;i++) rank[i]=n-(lower_bound(a+1,a+n+1,num[i])-a)+1;
	for(int i=1;i<=n;i++)
	{
	  if(!num[i]) ans[i]=C(n,k);
	  else
	  {
	  	sum1=lower_bound(b+1,b+n+1,num[i])-b-1;
	  	sum2=n-(lower_bound(a+1,a+n+1,num[i])-a);
	  	sum3=n-sum1-sum2-1;
	  	q=rank[i]-sum2-1;
	  	ans[i]=((LL)(C(sum3,q))*(LL)(C(sum1+sum2,k-q)))%mod;   //不乘2
	  	sum1=lower_bound(b+1,b+n+1,num[i]<<1)-b-1;
	  	sum2=n-(lower_bound(a+1,a+n+1,num[i]<<1)-a)+1;  //注意+1
	  	sum3=n-sum1-sum2-1;
	  	q=rank[i]-sum2-1;
	  	ans[i]=(ans[i]+(LL)(C(sum3,q))*(LL)(C(sum1+sum2,k-q-1))%mod)%mod;//要乘2所以剩余k-p-1个
	  }
	}
	for(int i=1;i<=n;i++) print(ans[i]),putchar('\n');
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值