BZOJ5368:[PKUSC2018]真实排名(组合数学)
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
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)翻倍,他的排名会变成第二,其他情况下都还是第一。
Solution
传说中的送温暖签到题QAQ?$pkuwc$的时候咋没有呢……
先把数$sort$一下,然后一个一个考虑。
对于当前数$b[i]$,分两种情况(如果$b[i]=b[i-1]$就答案等于前一个数的答案然后$continue$):
1、本身不翻倍,那么只有$b[i]$前面的某一段数是一定不能选的,因为如果选了这一段数的话就会有数超过$b[i]$从而改变排名……二分找一下就好了。
2、$b[i]$本身翻倍,这样$b[i]$后面的某一段数就必须得翻倍把$b[i]$翻下来,不然排名仍然会变。仍然二分找一下。
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<map> 4 #include<algorithm> 5 #define N (100009) 6 #define MOD (998244353) 7 using namespace std; 8 9 struct Node{int x,id,ans;}a[N]; 10 int n,k,x,pos,b[N],inv[N],fac[N],facinv[N]; 11 bool cmp1(Node a,Node b) {return a.x<b.x;} 12 bool cmp2(Node a,Node b) {return a.id<b.id;} 13 14 void Init() 15 { 16 inv[1]=fac[0]=facinv[0]=1; 17 for (int i=1; i<=n; ++i) 18 { 19 if (i!=1) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD; 20 fac[i]=1ll*fac[i-1]*i%MOD; facinv[i]=1ll*facinv[i-1]*inv[i]%MOD; 21 } 22 } 23 24 int C(int n,int m) 25 { 26 if (n<m) return 0; 27 return 1ll*fac[n]*facinv[m]%MOD*facinv[n-m]%MOD; 28 } 29 30 int main() 31 { 32 scanf("%d%d",&n,&k); 33 Init(); 34 for (int i=1; i<=n; ++i) 35 scanf("%d",&a[i].x), a[i].id=i; 36 sort(a+1,a+n+1,cmp1); 37 for (int i=1; i<=n; ++i) b[i]=a[i].x; 38 39 b[0]=-1; 40 for (int i=1; i<=n; ++i) 41 { 42 if (b[i]==b[i-1]) {a[i].ans=a[i-1].ans; continue;} 43 44 x=b[i]/2+(b[i]%2);//自己不翻倍 45 pos=lower_bound(b+1,b+i,x)-b; 46 a[i].ans=(a[i].ans+C(pos-1+n-i,k))%MOD;//[pos,i-1]不能翻倍,再算上i本身 47 48 x=b[i]*2;//自己翻倍 49 pos=lower_bound(b+i+1,b+n+1,x)-b; 50 pos--;//[i+1,pos]要翻倍 51 if (pos-i>k-1) continue; 52 a[i].ans=(a[i].ans+C(i-1+n-pos,k-1-(pos-i)))%MOD; 53 } 54 sort(a+1,a+n+1,cmp2); 55 for (int i=1; i<=n; ++i) 56 printf("%d\n",a[i].ans); 57 }