題意:
個範圍,求所有符合限制的單調不增序列的元素和的總和。
解題思路:
因爲是a是單調不降的,所以他們區間的左端點應該是單調不降的,右端點是單調不增的。可以分區間討論。
2n個點劃分出2n個區間,然後用表示考慮了前i個區間,選擇了j個數字的符合條件的序列的元素和。用表示前i個區間選了j個數字的方案數,那麼枚舉有多少個數在當前區間範圍內即可轉移。
怎麼轉移呢?
區間有x個數字,可重複選出y個數字組成單調不增序列的方案數,可以轉換爲有x個桶,放y個小球的方案數。那麼用隔板法我們知道方案數爲.
這樣前面的總和要乘上這麼多的方案數。然後再看當前新加的數字的貢獻:因爲是所有方案的總和,所以可以取平均,在選一個數字相當於貢獻。那麼選個對的額外貢獻爲:
其中單個數字貢獻爲
數字個數爲
前面區間選取方案爲
當前區間選取方案數用隔板法算一下
這樣就得到了的轉移。
的轉移就是 的累加了。
具體看代碼吧:
細節:
- 隔板法算出來的組合數不要預處理,直接算就行了,因爲數字個數很少。
- 在計算的轉移的時候與區間端點做乘之前先模,不然爆long long(63行)
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
/*注意爆long long*/
const int maxn = 205;
ll cc[200];
int num = 0;
int n;
ll l[55], r[55];
const ll mod = 998244353;
ll dp[200][200];
ll f[200][200];
ll fac[maxn], ifac[maxn], inv[maxn];
ll qm(ll a, ll b){ll res = 1; while(b) {if(b&1) res=res*a%mod; a = a*a%mod; b>>=1;} return res;}
ll Choose(ll a, ll b){//a個可選的數字,b個要放的數 C(b+a-1, b)
ll res = 1;
for(ll i = a; i < b+a; ++i) res = i%mod*res%mod;
for(ll i = 2; i <= b; ++i) res = res*inv[i]%mod;
return res;
}
int main()
{
fac[0] = ifac[0] = 1;
for(int i = 1; i < maxn; ++i) fac[i] = fac[i-1]*i%mod, ifac[i] = qm(fac[i], mod-2), inv[i] = qm(i, mod-2);
cin>>n;
for(int i = 1; i <= n; ++i){
scanf("%lld", &l[i]); l[i] = max(l[i], l[i-1]);
cc[++num] = l[i];
//cout<<"L:"<<l[i]<<endl;
}
for(int i = 1; i <= n; ++i){
scanf("%lld", &r[i]);
//cc[++num] = r[i]+1;
//cout<<"R:"<<r[i]+1<<endl;
}
cc[++num] = r[n]+1;
for(int i = n-1; i >= 1; --i){
r[i] = min(r[i], r[i+1]);
cc[++num] = r[i]+1;
}
sort(cc+1,cc+1+num);
num = unique(cc+1,cc+1+num)-cc-1;
assert(num < 200);
ll inv2 = (mod+1)/2;
f[0][0] = 1;
for(int i = 1; i < num; ++i){
dp[i][0] = 0;
f[i][0] = 1;
ll L = cc[i], R = cc[i+1]-1;
//cout<<"L:"<<L<<" R:"<<R<<endl;
for(int j = 1; j <= n; ++j){
dp[i][j] = dp[i-1][j];
f[i][j] = f[i-1][j];
for(int k = j; k > 0; --k){
if(l[k] <= L && R <= r[k]){
//cout<<"i:"<<i<<" j:"<<j<<" k:"<<k<<" L:"<<L<<" R:"<<R<<endl;
dp[i][j] = (dp[i][j] +
dp[i-1][k-1]*Choose(R-L+1, j-k+1)%mod +
f[i-1][k-1]*Choose(R-L+1, j-k+1)%mod*(R%mod+L%mod)%mod*inv2%mod*(j-k+1)%mod )%mod;
f[i][j] = (f[i][j] + f[i-1][k-1]*Choose(R-L+1, j-k+1)%mod)%mod;
//cout<<"dp:"<<dp[i][j]<<endl;
}else break;
}
// cout<<"i:"<<i<<"j:"<<j<<" dp:"<<dp[i][j]<<endl;
}
}
//cout<<dp[1][1]<<endl;
ll ans = dp[num-1][n];
//assert(ans > 0);
cout<<ans<<endl;
}
/*
2
1 2
3 4
*/