题面
考虑一个长度为
n
n
的序列Gobo Sort之后有序的期望尝试次数是
其中 ai a i 表示 i i 在序列中出现的次数。
那么就是我们可以把分配给 al,..,ar a l , . . , a r ,使得 ∏ri=lai! ∏ i = l r a i ! 尽可能小。
注意到一个性质,假设 x≤y x ≤ y ,那么 x!y!>(x−1)!(y+1)! x ! y ! > ( x − 1 ) ! ( y + 1 ) ! ,所以大概就是要让 al,...,ar a l , . . . , a r 尽量平均。
只要二分 min(al,...,ar) min ( a l , . . . , a r ) 然后判断 m m 是否够分配即可。
复杂度。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
#define M 10200010
#define ll long long
using namespace std;
const int mod=998244353;
int n,m,sz,L,R,a[N],z[N],cnt[N],lp,rp;
ll fac[M];
ll ksm(ll a,int b){ll r=1;for(;b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;}
int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
ll check(ll x)
{
ll tot=0;
tot=x*(R-L-(rp-lp));
if(tot>m) return tot;
for(int i=lp;i<=rp&&tot<=m;i++)
tot+=max(x-cnt[i],0ll);
return tot;
}
int main()
{
fac[0]=1;
for(int i=1;i<=M-10;i++)
fac[i]=fac[i-1]*i%mod;
int ca=read();
while(ca--)
{
for(int i=1;i<=n;i++)
cnt[i]=0;
n=read();m=read();L=read();R=read();
for(int i=1;i<=n;i++)
a[i]=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
z[i]=a[i];
sz=unique(z+1,z+n+1)-z-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(z+1,z+sz+1,a[i])-z;
lp=lower_bound(z+1,z+sz+1,L)-z;
rp=upper_bound(z+1,z+sz+1,R)-z-1;
for(int i=1;i<=n;i++)
cnt[a[i]]++;
ll lx=0,rx=m+n;
while(lx<rx)
{
ll mid=(lx+rx)>>1;
if(check(mid)<=m) lx=mid+1;
else rx=mid;
}
ll ans=ksm(fac[lx-1],R-L-(rp-lp));
for(int i=1;i<=sz;i++)
{
if(i>=lp&&i<=rp) ans=ans*fac[max((ll)cnt[i],lx-1)]%mod;
else ans=ans*fac[cnt[i]]%mod;
}
ans=ans*ksm(lx,m-check(lx-1))%mod;
ans=fac[n+m]*ksm(ans,mod-2)%mod;
printf("%lld\n",ans);
}
return 0;
}