Wannafly Winter Camp 2020 Day 6D 递增递增 - dp,组合数学

给定两个常为 \(n\) 的序列 \(l_i,r_i\),问夹在它们之间 ( \(\forall i, l_i \leq a_i \leq r_i\) ) 的不降序列的元素总和。

Solution

先搞一波离散化,把

\(f[i][j]\) 表示处理完了 \(a[1\dots i]\),且 \(a[i]\) 在第 \(j\) 个区间内的总和, \(g[i][j]\) 为方案数

考虑运用分段的思想,枚举下一段的结束点 \(p\),以及下一段所在区间 \(k\),就可以暴力转移到 \(f[p][k]\)
\[ Af[i][j] + Bg[i][j] \to f[p][k] \\ Ag[i][j] \to g[p][k] \]
其中 \(A\) 是方案数, \(B\) 是总和,运用插板法与期望的线性性质得
\[ t=p-i,\quad A=C_{R_k-L_k+t}^t,\quad B=\frac{t(L_k+R_k)}{2}\cdot C_{R-L+t}^t \]
组合数如果每个都暴力计算复杂度是 \(O(t\log V)\) 的。显然 \(C_{R-L+t}^t=\frac{(R-L+t)!}{(R-L)!t!}\),于是 \(C_{R-L+t}^t=C_{R-L+t-1}^{t-1} \cdot \frac{R-L+t}{t}\)

但是考虑到 \(R_k-L_k\) 之和 \(k\) 相关,所以我们需要用的组合数只有 \(O(n^2)\) 个,于是花费 \(O(n^2 \log V)\) 时间暴力预处理 \(c[k][t]=C_{R_k-L_k+t}^t\) 即可。

Warning: 运算过程会爆 long long

#include <bits/stdc++.h>
using namespace std;
#define int __int128
const bool dbg = 0;
const int N = 105;
const int mod = 998244353;
const int r2 = 499122177;
int f[N][N],g[N][N],c[N][N],n,L[N],R[N],l[N],r[N],pos[N],ind;
map<int,int> mp;
int qpow(int p,int q) {return ((q&1)?p:1) * (q?qpow(p*p%mod,q/2):1) % mod;}
int inv(int p) {return qpow(p,mod-2);}
void read(int &x) {
    long long a;
    cin>>a;
    x=a;
}
void write(int x) {
    cout<<(long long)x;
}
signed main() {
    read(n);
    for(int i=1;i<=n;i++) read(l[i]), mp[l[i]]++;
    for(int i=1;i<=n;i++) read(r[i]), r[i]++, mp[r[i]]++;
    for(auto i=mp.begin();i!=mp.end();i++) i->second=++ind, pos[ind]=i->first;
    for(int i=1;i<ind;i++) L[i]=pos[i], R[i]=pos[i+1];
    for(int i=1;i<=n;i++) l[i]=lower_bound(L+1,L+ind,l[i])-L, r[i]=lower_bound(R+1,R+ind,r[i])-R;
    for(int i=1;i<ind;i++) R[i]--;
    for(int i=1;i<ind;i++) {
        c[i][0]=1;
        for(int j=1;j<=n;j++) c[i][j]=c[i][j-1]*(((R[i]-L[i]+j)%mod+mod)%mod)%mod*inv(j)%mod;
    }
    g[0][0]=1;
    for(int i=0;i<=n;i++) {
        for(int j=0;j<ind;j++) if(((i==0)^(j==0))==0) {
            int lb=0,rb=ind;
            for(int p=i+1;p<=n;p++) {
                lb=max(lb,l[p]);
                rb=min(rb,r[p]);
                for(int k=j+1;k<ind;k++) {
                    if(lb<=k && k<=rb) {
                        f[p][k] += c[k][p-i]*f[i][j]%mod
                            + (p-i)*(L[k]+R[k])%mod*r2%mod*c[k][p-i]%mod*g[i][j]%mod;
                        f[p][k] %= mod;
                        g[p][k] += c[k][p-i]*g[i][j]%mod;
                        g[p][k] %= mod;
                    }
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<ind;i++) ans+=f[n][i], ans%=mod;
    write(ans);
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12363573.html