题解:P14636 [NOIP2025] 清仓甩卖 / sale(民间数据)
LinkCatTree · · 题解
第一次正赛切紫,留念。
以下的
正难则反,考虑统计贪心策略不优的方案数。首先手动模拟一下样例,我们发现当且仅当一个较大的
我们讨论一下
我们发现我们需要在决策完
显然直接枚举
于是我们可以省去枚举
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x=0,ch=getchar();
while(!isdigit(ch)) ch=getchar();
for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch&15);
return x;
}
using ll=long long;
const ll mod=998244353;
const int N=5005;
int c,T,n,m;
struct Candy {
int val,id;
Candy(int val=0,int id=0) {this->val=val,this->id=id;}
inline bool operator <(const Candy& tmp) const {
if(val==tmp.val) return id<tmp.id;
return val>tmp.val;
}
} a[N];
inline ll quickpow(ll base,ll p) {
ll tmp=1;
for(;p;p>>=1) {
if(p&1) tmp=tmp*base%mod;
base=base*base%mod;
}
return tmp;
}
ll pw[N],fact[N],inv[N];
inline void init() {
static const int s=5000;
pw[0]=fact[0]=inv[0]=1;
for(int i=1;i<=s;i++) {
pw[i]=pw[i-1]<<1;
if(pw[i]>=mod) pw[i]-=mod;
}
for(int i=1;i<=s;i++) {
fact[i]=fact[i-1]*i%mod;
inv[i]=quickpow(fact[i],mod-2);
}
return ;
}
inline ll C(int n,int m) {
if(n<0||m<0||n<m) return 0;
return fact[n]*inv[m]%mod*inv[n-m]%mod;
}
int main() {
c=read(),T=read(),init();
while(T--) {
n=read(),m=read();
for(int i=1;i<=n;i++) a[i].val=read(),a[i].id=i;
sort(a+1,a+1+n); ll ans=0;
for(int i=1;i<n;i++) {
int q=lower_bound(a+1,a+1+n,Candy(a[i].val>>1,0))-a;
for(int j=i+1,k=n;j<q;j++) {
if(a[j].val==a[i].val) continue ;
while(k>=q&&a[j].val+a[k].val<a[i].val) k--;
(ans+=C(j-2,m-i-1)*pw[n-k])%=mod;
}
}
if((ans=pw[n]-ans)<0) ans+=mod;
printf("%lld\n",ans);
}
return 0;
}