题解:P14636 [NOIP2025] 清仓甩卖 / sale(民间数据)
代码等公开再说。
多亏 T3 过于险恶,我在 12:30 的时候做出了回去优化 T2
先将物品价格从大到小排序。
我们可以想一下背包的时候什么情况下按性价比排序是错的。
比如说背包大小是
所以这个题显然也是因为放了一个
那么很显然买东西花了
注意我们要找到第一个
然后计算
考虑直接先扔
实现不难吧,等代码公开了我再更新。
upd on 2025.12.3
有个 sb 没预处理 2 的幂导致写成了
这是预处理
#include<bits/stdc++.h>
using namespace std;
#define gc getchar
#define pc putchar
#define int long long
const int N = 5010, M = N * 2, mod = 998244353;
int sub, T, n, m, a[N], fr[M], ifr[M], bit[N];
int read() {
int x = 0; char ch = gc();
while(ch < '0' || ch > '9') ch = gc();
while(ch >= '0' && ch <= '9') x = x * 10 + (ch ^ 48), ch = gc();
return x;
}
void write(int x) {
if(x == 0) {pc('0'); return ;}
int tot = 0; char s[15];
while(x) s[tot++] = x % 10 + '0', x /= 10;
while(tot--) pc(s[tot]);
}
int Pow(int a, int b) {
int ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod; b >>= 1;
}
return ans;
}
void Add(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
}
void Sub(int &x, int y) {
x -= y;
if(x < 0) x += mod;
}
void init(const int m = 10004) {
fr[0] = ifr[0] = 1;
for(int i = 1; i <= m; i++) fr[i] = fr[i - 1] * i % mod;
ifr[m] = Pow(fr[m], mod - 2);
for(int i = m - 1; i; i--) ifr[i] = ifr[i + 1] * (i + 1) % mod;
}
int C(int n, int m) {
if(n < m || m < 0) return 0;
if(m == 0) return 1;
return fr[n] * ifr[m] % mod * ifr[n - m] % mod;
}
signed main() {
// freopen("sale.in", "r", stdin);
// freopen("sale.out", "w", stdout);
init();
sub = read(), T = read();
bit[0] = 1; for(int i = 1; i <= 5000; i++) bit[i] = bit[i - 1] * 2 % mod;
while(T--) {
n = read(), m = read();
for(int i = 1; i <= n; i++) a[i] = read();
sort(a + 1, a + 1 + n); reverse(a + 1, a + 1 + n);
int ans = 0;
for(int i = 1; i <= n; i++) {
int p = n + 1;
for(int j = i + 1; j <= n; j++) if(a[i] != a[j]) {
if(a[j] * 2 <= a[i]) break;
while(p && a[p - 1] < a[i] - a[j]) p--;
Add(ans, bit[n - p + 1] * C(j - 2, m - i - 1) % mod);
}
}
ans = (Pow(2, n) - ans + mod) % mod;
write(ans); pc('\n');
}
return 0;
}
// AFO on 2025.11.29