【题解】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;
}
posted @ 2026-03-28 11:11  Ming3398  阅读(5)  评论(0)    收藏  举报