P14636 [NOIP2025] 清仓甩卖 题解
Coffee_zzz · · 题解
合法的方案数并不好求,因此考虑正难则反,计算不合法的方案数。
首先尝试刻画一下不合法的条件。显然,如果小 R 购买的糖果是按照性价比排序后的一段前缀,则他买到的糖果一定是最优的;因此,我们只需要考虑中间有一些糖果因为买不起而没有买的情况。设:
- 小 R 在只剩下恰好一元钱前,购买的最后一颗满足
w_i=1 的糖果为y (其性价比为a_y ); - 小 R 在只剩下恰好一元钱后,遇到的第一颗满足
w_i=2 的糖果的编号为x (其性价比为\dfrac {a_x} 2 ); - 小 R 在只剩下恰好一元钱后,遇到的第一颗满足
w_i=1 的糖果的编号为z (其性价比为a_z );特殊地,若不存在糖果z ,则认为z=n+1 ,其原价a_z 等于0 ;
则小 R 会先购买糖果
显然,当
我们将所有糖果按照原价从大到小排序,并将此时的下标作为糖果的编号。考虑枚举
- 对于
i\in [1,x-1] ,w_i 可以等于1 或2 ; - 对于
i=x ,w_i 需要等于2 ; - 对于
i\in [x+1,y-1] ,w_i 可以等于1 或2 (若w_i=1 则它会被放在x 前面,若w_i=2 则它会被放在x 后面); - 对于
i=y ,w_i 需要等于1 ; - 对于
i\in [y+1,u] ,w_i 需要等于2 ,因为如果w_i=1 的话糖果y 就不是剩下恰好一元钱前购买的最后一颗糖果了; - 对于
i\in [u+1,v] ,w_i 需要等于2 ,因为如果w_i=1 的话糖果z 就不满足a_x \gt a_y+a_z 了; - 对于
i\in [v+1,n] ,w_i 可以等于1 或2 ,因为它们都可以作为糖果z 。
同时,设
对于
于是我们只需要枚举
时间复杂度
const int N=5005,mod=998244353;
int n,m,fac[N],infac[N],pw[N],ans;
ll a[N];
int ksm(int a,int b){
int res=1;
while(b){
if(b&1) res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
void add(int &a,int b){
a+=b;
if(a>=mod) a-=mod;
}
int C(int n,int m){
return 1ll*fac[n]*infac[m]%mod*infac[n-m]%mod;
}
void init(){
fac[0]=infac[0]=pw[0]=1;
for(int i=1;i<N;i++) fac[i]=1ll*fac[i-1]*i%mod;
infac[N-1]=ksm(fac[N-1],mod-2);
for(int i=N-2;i>=1;i--) infac[i]=1ll*infac[i+1]*(i+1)%mod;
for(int i=1;i<N;i++) pw[i]=2*pw[i-1]%mod;
}
void solve(){
cin>>n>>m,ans=0,a[n+1]=0;
for(int i=1;i<=n;i++) cin>>a[i],a[i]=a[i]*2;
sort(a+1,a+n+1);
reverse(a+1,a+n+1);
for(int x=1;x<min(m,n);x++){
int y=x;
while(y<n&&a[x]/2<a[y+1]) y++;
int v=y;
while(v<n&&a[x]-a[y]<=a[v+1]) v++;
for(;a[y]<a[x];y--){
while(v<n&&a[x]-a[y]<=a[v+1]) v++;
int f=y-2,g=m-x-1;
if(f<g) continue;
add(ans,1ll*C(f,g)*pw[n-v]%mod);
}
}
cout<<(pw[n]+mod-ans)%mod<<endl;
}