[洛谷P5368] [PKUSC2018] 真实排名

[PKUSC2018]真实排名

题目描述

小 C 是某知名比赛的组织者,该比赛一共有 \(n\) 名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排名是:成绩不小于他的选手的数量(包括他自己)。例如如果 \(3\) 位选手的成绩分别是 \([1 , 2 ,2]\) ,那么他们的排名分别是 \([3,2,2]\)

拥有上帝视角的你知道所有选手的实力,所以在考试前就精准地估计了每个人的成绩,设你估计的第 \(i\) 个选手的成绩为\(A_i\),且由于你是上帝视角,所以如果不发生任何意外的话,你估计的成绩就是选手的最终成绩。

但是在比赛当天发生了不可抗的事故(例如遭受到了外星人的攻击),导致有一些选手的成绩变成了最终成绩的两倍,即便是有上帝视角的你也不知道具体是哪些选手的成绩翻倍了,唯一知道的信息是这样的选手恰好有 \(k\) 个。

现在你需要计算,经过了不可抗事故后,对于第 \(i\) 位选手,有多少种情况满足他的排名没有改变。

由于答案可能过大,所以你只需要输出答案对 \(998244353\) 取模的值即可。

输入格式

第一行两个正整数 \(n,k\)

第二行 \(n\) 个非负整数 \(A_1..A_n\)

输出格式

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

样例 #1

样例输入 #1

3 2
1 2 3

样例输出 #1

3
1
2

提示

对于 \(10\%\) 的数据,有 \(1\leq n\leq 15\)

对于 \(35\%\) 的数据,有 \(1\leq n\leq 10^3\)

另有 \(10\%\) 的数据,满足每个人的成绩都互不相同

另有 \(10\%\) 的数据,满足 \(0\leq A_i\leq 10^5\)

另有 \(10\%\) 的数据,满足 \(k=85\)\(0\leq A_i\leq 600\)

对于\(100\%\)的数据,有\(1\leq k < n\leq 10^5\)\(0\leq A_i\leq 10^9\)

考虑把所有 \(a\) 排序后处理。

\(a\) 数组中,如果第 \(i\) 个数不乘2,那么大于等于 \(a_i\) 的数随便乘,小于 \(a_i\) 的,要满足 \(2a_j<a_i\)\(a_j\) 才可以给 \(a_j\) 乘2.

如果第 \(i\) 个数乘了 2,那么 所有满足 \(a_i\le a_j,2a_i>a_j\) 的数都要乘个 2,其余随便。

用双指针维护即可。

小细节:

  1. 注意双指针时 while 里面两个都不去等。
  2. 注意处理组合数时不要把 \(k\) 减出界。
  3. 注意 \(2\times 0=0\),所以要特判 \(a_i=0\)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,P=998244353;
int n,k,a[N],f[N],id[N],inv[N],ans[N],iv[N],l,r;
int cmp(int x,int y)
{
	return a[x]<a[y];
}
int calc(int x,int y)
{
//	if(x==1&&y==0)
//		printf("%d %d %d\n",f[x],iv[y],iv[x-y]); 
	return 1LL*f[x]*iv[y]%P*iv[x-y]%P;
}
int main()
{
	iv[0]=inv[1]=iv[1]=f[0]=f[1]=1;
	scanf("%d%d",&n,&k);
	for(int i=2;i<=n;i++)
	{
		f[i]=1LL*f[i-1]*i%P;
		inv[i]=1LL*(P-P/i)*inv[P%i]%P;
		iv[i]=1LL*iv[i-1]*inv[i]%P;
	}
//	printf("%d\n",calc(2,2));
	for(int i=1;i<=n;i++)
		scanf("%d",a+i),id[i]=i;
	sort(id+1,id+n+1,cmp);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
	{
		r=max(r,i);
		if(i^1&&a[i]==a[i-1])
		{
			ans[id[i]]=ans[id[i-1]];
			continue; 
		}
//		printf("%d %d\n",l,r);
		while(a[l+1]*2<a[i])
			++l;
		ans[id[i]]=calc(l+n-i,k);
		while(r^n&&a[i]*2>a[r+1])
			++r;
//		printf("%d %d\n",i-1+n-r,k-r+i-1);
		if(r-i+1<=k)
			(ans[id[i]]+=calc(i-1+n-r,k-r+i-1))%=P;
//		printf("%d %d\n",l,r);
	}
	for(int i=1;i<=n;i++)
		printf("%d\n",ans[i]);
}
posted @ 2023-02-12 12:29  灰鲭鲨  阅读(49)  评论(0编辑  收藏  举报