题解:P14636 [NOIP2025] 清仓甩卖 / sale(民间数据)
题外话:这个题其实并没有像大家想的那么难写/有一车 corner case,实际上写起来很简单而且总共有
为了方便描述,以下记题面中的
第一步显然是考虑把条件刻画成一个简洁可做的形式。发现合法条件并不好刻画,正难则反,我们考虑什么时候不合法。
显然在大多数时候,直接贪心选性价比最高的肯定没有问题。唯一的例外可能是:我们先用一个体积小但价值也小的填了进去,可是实际上更优的体积更大的数却填不进去了。
也就是说,当且仅当最后剩余体积为
整理一下条件,如下图(
当然其实有个小 bug:有可能
我们发现,由于在分别确定完价值为
我们考虑“选出的数和为
也就是说,我们有
这一步显然可以直接范德蒙德卷积,如果你不会也很简单,考虑把后
别忘了我们还没考虑
如果你觉得听不太明白,可以看下面的图:
时间复杂度
#include <bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define fir first
#define sec second
#define chmin(a,b) a=min(a,b)
#define chmax(a,b) a=max(a,b)
#define pb push_back
const int inf=0x3f3f3f3f;
const int mod=998244353;
int C[5010][5010],pw[5010];
void init(int n)
{
pw[0]=1;
for(int i=1;i<=n;i++)pw[i]=(pw[i-1]<<1)%mod;
for(int i=0;i<=n;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;
}
}
int n,m,a[5010],ans;
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
ans=0;
for(int i=1;i<=n;i++)for(int j=i+1,k=0;j<=n;j++)if(a[i]*2>a[j]&&a[i]!=a[j])
{
while(k<j-1&&a[i]+a[k+1]<a[j])k++;
int sum=m-2-(n-j);
int cnt=n-i-1;
if(cnt<sum||sum<0)continue;
(ans+=1ll*pw[k]*C[cnt][sum]%mod)%=mod;
}
ans=(pw[n]-ans+mod)%mod;
cout<<ans<<'\n';
}
signed main()
{
init(5000);
int c,t;
cin>>c>>t;
while(t--)solve();
return 0;
}