【洛谷5368】[PKUSC2018] 真实排名(组合数学)

点此看题面

大致题意:(n)个数字,定义一个数的排名为不小于它的数的个数。现要随机将其中(k)个数乘(2),求对于每个数有多少种方案使其排名不变。

分类讨论

对于这种题目,我们可以分类讨论一下,假设当前考虑第(i)个数的答案。

(a_i)不被修改时,因为原先就(ge a_i)的数不可能在修改后(<a_i),所以我们就可以知道:

  • 原先就(ge a_i)的数可以随意修改。
  • 原先(<a_i)的数如果修改后(ge a_i)就不可以修改。

如果我们将原序列排序,设(t1)满足(2a_{t1}<a_ile 2a_{t1+1}),那么不可以修改的数就有(i-t1)个,而剩下的(n-(i-t1))个数可以任意修改,即方案数为:

[C_{n-(i-t1)}^k ]

(a_i)被修改时,因为原先就(<a_i)的数在修改后必然依旧(<a_i),所以我们就可以知道:

  • 原先就(<a_i)的数可以随意修改。
  • 原先就(ge2a_i)的数可以随意修改。
  • 原先(ge a_i)(<2a_i)的数必须修改。

如果我们将原序列排序,设(t2)满足(a_{t2}<2a_ile a_{t2+1}),那么必须修改的数就有(t2-i+1)个(注意(a_i)必须修改),而剩下的(n-(t2-i+1))个数可以任意修改,即方案数为:

[C_{n-(t2-i+1)}^{k-(t2-i+1)} ]

而对于(t1,t2),我们可以在枚举(i)的同时进行维护。

特殊情况

注意,有两种特殊情况会把上面的推理过程卡掉。

  • (a_i=0)
    • 问题:我们会发现,根据(t2)的定义,此时(t2<i),会出锅。
    • 解决方案:每次将(t2)(i)(max)
  • 出现相同的(a_i)
    • 问题:在讨论过程中一些边界细节问题上会出锅。
    • 解决方案:不难发现,相同的(a_i)答案是一样的。而对于一些相同的(a_i),其中第一个(a_i)用上述方法计算答案是不会出错的。因此将所有相同的(a_i)的答案都赋为第一个(a_i)的答案即可。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg 
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define X 998244353
#define C(x,y) ((x)>=(y)?1LL*Fac[x]*IFac[y]%X*IFac[(x)-(y)]%X:0)
using namespace std;
int n,k,ans[N+5],Fac[N+5],IFac[N+5];
struct data {int p,v;I bool operator < (Con data& o) Con {return v<o.v;}}s[N+5];
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
	RI i,t1,t2,lst;for(scanf("%d%d",&n,&k),Fac[0]=i=1;i<=n;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
	for(IFac[n]=Qpow(Fac[n],X-2),i=n-1;~i;--i) IFac[i]=1LL*IFac[i+1]*(i+1)%X;//预处理阶乘逆元
	for(i=1;i<=n;++i) scanf("%d",&s[s[i].p=i].v);//读入
	for(sort(s+1,s+n+1),s[0].v=-1,i=1,t1=t2=0;i<=n;++i)//记得排序
	{
		if(s[i].v==s[i-1].v) {ans[s[i].p]=lst;continue;}//如果与上一个数一样
		W(t1^n&&2*s[t1+1].v<s[i].v) ++t1;W(t2^n&&s[t2+1].v<2*s[i].v) ++t2;t2<i&&(t2=i);//更新t1,t2
		ans[s[i].p]=lst=(C(n-(i-t1),k)+(t2-i<=k?C(n-(t2-i+1),k-(t2-i+1)):0))%X;//计算答案
	}
	for(i=1;i<=n;++i) printf("%d
",ans[i]);return 0;//输出答案
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5368.html