【题解】P14636 [NOIP2025] 清仓甩卖
零
\(link\)
中位紫
壹:不合法情况
定义 \(W=1\) 的物品为一类物品,\(W=2\) 的物品为二类物品
不合法当且仅当,存在一类物品 \(x\) , \(z\) ,二类物品 \(y\)
对性价比降序排序有 \(x...(y)...z < (x)...y...(z)\) 的总收益
这种情况仅在购买 \(x\) 后总花费为 \(m-1\) 时出现
贰:计数
一
我们对不合法情况计数,然后用总方案减去它
首先对 \(a\) 降序排序
我们只需要考虑三个关键点 \(x,y,z\) 它们之间满足 $x<y<z \land 2a_y>a_x \land a_z<a_x-a_y $
此时数轴划分为若干段,有

二
定义 \(E(x,y)\) 表示已知 \(x,y\) 的情况下 \([1,y]\) 范围的非法情况个数
对于 \([1,x-1]\) 段,设二类物品有 \(p\) 个,则花费为 \(x-1+p\)
对于 \([x+1,y-1]\) 段,设一类物品有 \(q\) 个,则花费为 \(q\)
此时有 \(1+x-1+p+q=m-1\) 化简得到 \(p+q=m-1-x\)
要在 \(y-2\) 个物品中选出 \(p+q=m-1-x\) 个特殊物品,情况有 \(E(x,y)=\binom{y-2}{m-x-1}\) 种情况
三
接下来我们要拼接上 \(z\)
一种显然的想法是枚举 \(z\) 的位置,求 \(E* \prod_{z=y+1}^{n} 2 [a_z<a_x-a_y]\)
全部拼一块有 \(\sum_{x=1}^{n}\sum_{y=x+1}^{n}\binom{y-2}{m-x-1}\prod_{z=y+1}^{n}2 [2a_y>a_x \land a_z<a_x-a_y]\)
容易发现 \(a_z\) 的下界随 \(a_y\) 的上界变小而变大 ,即 \(z\) 随着 \(y\) 右移而左移,所以可以用双指针优化一维
复杂度 \(O(n^2)\)
参:代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5010,mod=998244353;
int a[N];
int fact[N],invf[N];
int pow2[N];
int ksm(int a,int b){
int res=1;
a%=mod;
while(b){
if(b&1){
res*=a;
res%=mod;
}
a*=a;
b>>=1;
a%=mod;
}
return res;
}
int inv(int x){
return ksm(x,mod-2);
}
int C(int n,int m){
if(n<0||m<0||n-m<0) return 0;
return 1LL*fact[n]*invf[m]%mod*invf[n-m]%mod;
}
void solve(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n,greater<int>());
//for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<"\n";
int ans=0;
for(int x=1;x<=n;x++){
int z=n;
for(int y=x+1;y<=n;y++){
if(2*a[y]<=a[x]) continue;
if(a[y]==a[x]) continue;
int base=C(y-2,m-x-1);
while(a[z]+a[y]<a[x]) z--;
int res=pow2[n-z];
ans+=base*res%mod;
ans%=mod;
}
}
ans=ksm(2,n)-ans;
ans=(ans%mod+mod)%mod;
cout<<ans<<"\n";
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int c,t;cin>>c>>t;
fact[0]=1;for(int i=1;i<N;i++) fact[i]=fact[i-1]*i%mod;
invf[N-1]=inv(fact[N-1]);
for(int i=N-2;i>=0;i--) invf[i]=invf[i+1]*(i+1)%mod;
pow2[0]=1;for(int i=1;i<N;i++) pow2[i]=pow2[i-1]*2%mod;
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号