首先有暴力的30分做法, 设 f[i][j] 为还是i, j 个的概率
然后 v[i] 为当前的数列
然后你会毒瘤地发现,type = 1 时它是个等差的,type = 2时是一个二阶等差的
也就是说,我们只需要维护前3项,然后暴力插出后面的就可以了
每次分成A 和 n - A 两堆的时候,我们需要插出 A+1,A+2, A+3的值,然后类似上面的 v 解决当前的前3项
现在唯一的问题是 f 数组,显然不能 n^2 处理
发现分子和分母是定下来的
分母是
分子是
然后两堆的取法是一个组合数
30 pts (没想到矩阵快速幂啊)
#include<bits/stdc++.h>
#define N 105
using namespace std;
typedef long long ll;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = (cnt << 1) + (cnt << 3) + (ch-'0'), ch = getchar();
return cnt * f;
}
const int Mod = 998244353;
int n, m, type;
ll f[N][N], v[N], a[N], b[N];
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll power(ll a, ll b){
ll ans = 1;
for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
int main(){
n = read(), m = read(), type = read();
for(int i=1; i<=n; i++) v[i] = (type == 1 ? i : mul(i, i));
for(int Case=1; Case<=m; Case++){
int A = read();
for(int i=1; i<=A; i++) a[i] = v[i];
for(int i=1; i<=n-A; i++) b[i] = v[i + A];
memset(f, 0, sizeof(f));
f[A][n-A] = 1;
for(int i=A; i>=0; i--){
for(int j=n-A; j>=0; j--){
ll inv = power(i + j, Mod - 2);
if(i) f[i-1][j] = add(f[i-1][j], mul(f[i][j], mul(inv, i)));
if(j) f[i][j-1] = add(f[i][j-1], mul(f[i][j], mul(inv, j)));
}
} memset(v, 0, sizeof(v));
for(int i=n; i>=1; i--){
ll inv = power(i, Mod - 2);
for(int j=min(i, A); j>=0; j--){
int k = i - j; if(k > n - A) break;
if(j) v[i] = add(v[i], mul(f[j][k], mul(a[j], mul(inv, j))));
if(k) v[i] = add(v[i], mul(f[j][k], mul(b[k], mul(inv, k))));
}
}
}
int q = read();
for(int i=1; i<=q; i++){
int x = read(); printf("%lld\n", v[x]);
} return 0;
}
100 pts
#include<bits/stdc++.h>
#define N 10000050
using namespace std;
typedef long long ll;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = (cnt << 1) + (cnt << 3) + (ch-'0'), ch = getchar();
return cnt * f;
}
const int Mod = 998244353;
int n, m, type;
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll power(ll a, ll b){
ll ans = 1;
for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
ll fac[N], inv[N];
void prework(){
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i=2; i<=n; i++) fac[i] = mul(fac[i-1], i);
inv[n] = power(fac[n], Mod - 2);
for(int i=n-1; i>=2; i--) inv[i] = mul(inv[i+1], i+1);
}
ll f[5], g[5], h[5], pre[5], suf[5];
ll C(int n, int m){ return mul(fac[n], mul(inv[n-m], inv[m]));}
ll Get(int A, int B, int i, int j){
if(A < i || B < j) return 0;
ll ans = power(mul(fac[A + B], inv[i + j]), Mod - 2);
ans = mul(ans, C(A + B - i - j, A - i));
ans = mul(ans, mul(mul(fac[A], inv[i]), mul(fac[B], inv[j])));
return ans;
}
const int up = 3;
ll lagrange(ll *y, int n){
if(n <= up) return y[n]; pre[0] = suf[up + 1] = 1;
for(int i=1; i<=up; i++) pre[i] = mul(pre[i-1], n - i);
for(int i=up; i>=1; i--) suf[i] = mul(suf[i+1], n - i);
ll ans = 0;
for(int i=1; i<=up; i++){
ll tmp = mul(y[i], mul(mul(inv[i-1], inv[up-i]), mul(pre[i-1], suf[i+1])));
ans = ((up - i) & 1) ? add(ans, Mod - tmp) : add(ans, tmp);
} return ans;
}
int main(){
freopen("landlords.in","r",stdin);
freopen("landlords.out","w",stdout);
n = read(), m = read(), type = read(); prework();
for(int i=1; i<=3; i++) f[i] = (type == 1 ? i : mul(i, i));
for(int Case = 1; Case <= m; Case ++){
int A = read();
swap(f, g);
for(int i=1; i<=3; i++) h[i] = lagrange(g, A + i);
memset(f, 0, sizeof(f));
for(int i=0; i<=3; i++){
for(int j=0; i+j <= 3; j++){
if(i + j == 0) continue;
ll tmp = Get(A, n - A, i, j);
ll inv = power(i + j, Mod - 2);
f[i + j] = add(f[i + j], mul(tmp, mul(g[i], mul(i, inv))));
f[i + j] = add(f[i + j], mul(tmp, mul(h[j], mul(j, inv))));
}
}
}
int q = read();
while(q--){
int x = read(); printf("%lld\n", lagrange(f, x));
} return 0;
}