https://www.luogu.com.cn/problem/P4707
题解:
扩展min-max容斥见:
https://www.cnblogs.com/coldchair/p/13404911.html
一开始使(k=n-k+1),意义转为第(k)大。
然后套容斥:
(sum_{T} min(T)*inom{|T|-1}{k-1}*(-1)^{|T|-k})
在此题中,很容易得到(min(T)=frac{m}{sum{x in T} ~ a[x]})
考虑一个dp,(f[i][j][u])表示前(i)个确定了,(|T|=j),(sum{x in T} ~ a[x]=u)的方案数,可以获得70p。
((-1)^{|T|-k})可以放进dp里。
注意到(kle 10),观察(inom{|T|-1}{k-1}),联想到组合数性质:(inom{A+1}{B}= inom{A}{B-1}+ inom{A}{B})。
只要维护(inom{|T|-1}{0..k-1}),当(|T|++)时,就可以推了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;
const int mo = 998244353;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
const int N = 10005;
int n, k, m;
int a[N];
ll fac[N], nf[N], inv[N];
void build(int n) {
fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
nf[n] = ksm(fac[n], mo - 2); fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
fo(i, 1, n) inv[i] = nf[i] * fac[i - 1] % mo;
}
ll C(int n, int m) {
return n < m ? 0 : fac[n] * nf[m] % mo * nf[n - m] % mo;
}
ll f[2][11][N][2];
int o;
void add(ll &x, ll y) { (x += y) %= mo;}
int main() {
build(10000);
scanf("%d %d %d", &n, &k, &m);
fo(i, 1, n) scanf("%d", &a[i]);
k = n - k + 1;
memset(f, 0, sizeof f);
f[o][0][0][0] = (k % 2 ? -1 : 1);
int sm = 0;
fo(i, 1, n) {
memset(f[!o], 0, sizeof f[!o]);
fo(u, 0, sm) {
fo(j, 0, k - 1) {
add(f[!o][j][u + a[i]][1], -(f[o][j][u][1] + (j ? f[o][j - 1][u][1] : 0)));
add(f[!o][j][u + a[i]][1], -f[o][j][u][0]);
add(f[!o][j][u][0], f[o][j][u][0]);
add(f[!o][j][u][1], f[o][j][u][1]);
}
}
sm += a[i];
o = !o;
}
ll ans = 0;
fo(u, 0, m) {
ans = (ans + inv[u] * m % mo * f[o][k - 1][u][1]) % mo;
}
ans = (ans % mo + mo) % mo;
pp("%lld
", ans);
}