题解:P14636 [NOIP2025] 清仓甩卖 / sale(民间数据)
看到好多人说难写难调,我的做法实现貌似很简单啊!
考虑什么情况会算错。
如果性价比最高的是
但如果选了
也就是说,记
我们称上述错误中第一件
尝试直接对这个结构进行计数。首先把所有
然后,枚举特殊物品
对于性价比大于
- 对于原价已经大于
a_y 的物品,无论价格总会被选,会消耗1 或2 元。这样的物品有n-y 个。 - 对于原价在
a_x 和a_y 之间的物品,w=1 时性价比优于y 会被选,会消耗0 或1 元。这样的物品有y-x-1 个。 - 对于原价在
\frac{a_y}{2} 和a_x 之间的物品,由之前错解的形态可知一定不会被选,只能w=2 并消耗0 元。
以上三种情况涵盖了
也就是说,上述所有物品中我们会花掉
对于原价小于
相当于找到最大的
时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=10005,P=998244353;
int n,m,a[N];
int pow2[N],C[N][N];
void init(){
pow2[0]=1; for(int i=1;i<=10000;++i) pow2[i]=(2ll*pow2[i-1])%P;
C[0][0]=1;
for(int i=1;i<=10000;++i) {
C[i][0]=1;
for(int j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
}
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int ID,T; cin>>ID>>T;
init();
while(T--) {
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+n+1);
int ans=0;
for(int i=1;i<=n;++i) {
int pos=0;
for(int j=i+1;j<=n;++j) {
if(a[i]==a[j]||(m-2-(n-j))<0) continue;
if(a[j]>=a[i]*2) break;
while(pos<n&&a[pos+1]+a[i]<a[j]) pos++;
ans=(ans+1ll*C[n-i-1][m-2-(n-j)]*pow2[pos])%P;
}
}
cout<<(pow2[n]-ans+P)%P<<'\n';
}
return 0;
}
希望这篇题解能够帮到你!