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;
}