typedeflonglong ll; constint N = 3005; constint P = 998244353;
int n, m; int a[N]; ll f[N][N]; ll fact[N], finv[N];
voidprework(int n); ll qpow(ll a, ll b); ll C(int n, int m);
intmain() { cin >> n >> m; prework(n); for(int i = 1; i <= n; i++) cin >> a[i]; f[0][0] = 1; for(int i = 1; i <= m; i++) for(int j = 0; j <= n; j++) { if(j) (f[i][j] += f[i-1][j-1]) %= P; (f[i][j] += f[i-1][j]*j*2%P) %= P; } ll ans = 0; for(int i = 1; i <= n; i++) for(int j = i; j <= n; j++) { if(j != i and a[j-1] > a[j]) break; (ans += f[m][i-1+n-j] * C(i-1+n-j,i-1)%P) %= P; } for(int i = 0; i <= n; i++) (ans += f[m][n] * C(n,i)%P) %= P; cout << ans << "\n"; }
ll C(int n, int m) { if(n < m or n < 0or m < 0) return0; return fact[n] * finv[m]%P * finv[n-m]%P; } voidprework(int n) { fact[0] = 1; for(int i = 1; i <= n; i++) fact[i] = fact[i-1]*i%P; finv[n] = qpow(fact[n], P-2); for(int i = n-1; i >= 0; i--) finv[i] = finv[i+1]*(i+1)%P; } ll qpow(ll a, ll b) { ll ans = 1; a %= P; for(; b; b >>= 1, a = a*a%P) if(b&1) ans = ans*a%P; return ans; }
Wine Thief
ARC120F
直接算显然没法算,于是我们考虑计算每个数的贡献,即 ai 乘以包含 ai 的合法的方案数。
设 G(n,k,i) 表示 n 个数中选 k 个, 必须选第 i 个数的合法方案数,所以答案就是:
i=1∑nai∗G(n,k,i)
但是 G(n,k,i) 比较难求,暴力求的话只能枚举这个数前面后面选了多少个,如果能用其他的 G 值求的话会比较方便。
为了不枚举这个数前面后面选了多少个,我们可以将序列连接成环来考虑。
把序列连接成环后只多了一个限制: a1 和 an 不能同时选。
先把 G(n,k,i) 的定义放到环上变成 G′(n,k,i),因为环是旋转同构的,所以对于任意的 i ,他们的 G′(n,k,i) 都相同。
设 f(n,k) 为在一个长度为 n 的序列中,选出 k 个数的方案数,考虑把这 k 个数插入剩下的 n−k 个数之间的空隙中,所以 f(n,k)=Cn−k+1n 。
typedeflonglong ll; constint N = 3e5+10; constint P = 998244353;
int n, k, d; int a[N]; ll fact[N], finv[N]; ll pre[N];
voidprework(); ll F(int n, int k); ll f(int n, int k); ll C(int n, int m); ll qpow(ll a, ll b); ll G(int n, int k, int i);
intmain() { cin >> n >> k >> d; prework(); ll ans = 0; for(int i = 1; i <= n; i++) { int a; cin >> a; (ans += a*G(n,k,i)%P) %= P; } cout << ans << "\n"; }
voidprework() { fact[0] = 1; for(int i = 1; i <= n; i++) fact[i] = fact[i-1]*i%P; finv[n] = qpow(fact[n], P-2); for(int i = n-1; i >= 0; i--) finv[i] = finv[i+1]*(i+1)%P; for(int i = 0; i < n; i++) pre[i+1] = (pre[i] + F(n-i*4, k-i*2))%P; ll ans = 0; for(int i = 1; i <= n; i++) (ans += a[i]*G(n, k, i)%P) %= P; }
ll G(int n, int k, int i) { if(i <= 0) return0; if(i == 1) returnf(n-2, k-1); if(i > (n+1)/2) returnG(n, k, n-i+1); return (pre[i/2] + G(n-(i/2)*4, k-(i/2)*2, i%2))%P; } ll F(int n, int k) { if(n < 3) return k == 1; elsereturnf(n-3, k-1); } ll f(int n, int k) { returnC(n-k+1, k); } ll C(int n, int m) { if(n < m or n < 0or m < 0) return0; return fact[n]%P * finv[m]%P * finv[n-m]%P; } ll qpow(ll a, ll b) { ll ans = 1; a %= P; for(; b; b >>= 1, a = a*a%P) if(b&1) ans = ans*a%P; return ans; }