题解:P16416 【MX-X28-T5】「FAOI-R12」单人旅行
LastKismet · · 题解
考虑
考虑对此 DP。首先所有划分段的贡献容易
DP 转移直接枚举段长即可,因为段长不超过
void MAIN(){
// #define MultiTasks
const int N=5005;
sto int n;read(n);
sto int c[N],cnt[N];rep(i,1,n)read(c[i]),++cnt[chmin(c[i],n+1)];
sto mint a[N],b[N];rep(i,1,n)read(a[i]);rep(i,1,n)read(b[i]);
sto mint v[N][N],tv[N][N];rep(l,1,n){
v[l][l]=a[l]*l+b[l],tv[l][l]=a[l]*(l+1)+b[l];
rep(r,l+1,n)
v[l][r]=tv[l][r-1]*(a[r]*l+b[r]),
tv[l][r]=tv[l][r-1]*(a[r]*(r+1)+b[r]);
}tv[n+1][n]=1;
sto mint fc[N],iv[N];
fc[0]=1;rep(i,1,n)fc[i]=fc[i-1]*i;
iv[n]=1/fc[n];per(i,n,1)iv[i-1]=iv[i]*i;
#define A(n,m) (fc[n]*iv[(n)-(m)])
sto mint f[N][N];f[0][0]=1;
repl(i,0,n)rep(j,0,i)if(f[i][j].x)rep(k,1,cnt[i+1]+1){
if(i+k>n)break;
f[i+k][j+1]+=f[i][j]*A(cnt[i+1],k-1)*v[i+1][i+k];
if(k<=cnt[i+1])f[i+k][j]-=f[i][j]*A(cnt[i+1],k)*v[i+1][i+k];
}
mint ans;
rep(i,0,n)rep(j,0,i)if(f[i][j].x&&cnt[i+1]>=n-i)ans+=f[i][j]*A(cnt[i+1],n-i)*fc[j]*tv[i+1][n];
put(ans);
}