题解:P14636 [NOIP2025] 清仓甩卖 / sale(民间数据)

· · 题解

我觉得这题最多蓝。为啥都要范德蒙德卷积?我一度以为自己过了所有大样例的做法假了。

首先,注意到这是一个背包弱化版的贪心做法。

我们可以注意到,这个贪心是假的,当且仅当你选的一个 w=1,创飞了一个可能更优的 w=2

于是可以枚举那个没选的 w=2,再枚举那个创飞它的 w=1

先将原价排序。枚举到 i 位置 w=2 被创飞了,并且创飞它的是 jj 需要满足 a_j<a_i2\times a_j>a_i

可以发现:

然后 i-1 及之前的 w 之和加上 i+1\sim j-1w=1 的个数恰好是 m-2 才行。因为选了个 j 之后是 m-1,但是你把 j 删掉加入 i 更优可以凑到恰好 m

枚举 $j$ 找 $k$ 的过程双指针即可。复杂度 $O(n^2)$。 ```cpp #include<iostream> #include<algorithm> #define int long long using namespace std; int cid,t,n,m; const int nr=5010,mod=998244353; int c[nr][nr],power[nr]; int a[nr]; bool cmp(int x,int y){ return x>y; } int C(int x,int y) { if(x<0||y<0||x<y)return 0; return c[x][y]; } signed main() { ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>cid>>t; for(int i=0;i<=5000;i++) { c[i][0]=1; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; } power[0]=1; for(int i=1;i<=5000;i++)power[i]=power[i-1]*2%mod; while(t--) { cin>>n>>m; for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+n+1,cmp); int ans=0; for(int i=1;i<=n;i++) { int pos=i; while(pos<=n&&a[pos]==a[i])pos++; pos--; int k=n+1; for(int j=pos+1;j<=n&&a[j]*2>a[i];j++) { while(a[j]+a[k-1]<a[i])k--; ans+=C(j-2,m-i-1)*power[n-k+1]; ans%=mod; } } cout<<(power[n]+mod-ans)%mod<<'\n'; } return 0; } ```