传送门
题解:
首先考虑一个区间DP,枚举区间中的最大值最右边的位置,左边所有点不大于这个位置,右边所有点严格小于这个位置。
容易发现这个位置只能是中间几个地方。
设 d p [ l ] [ r ] [ x ] dp[l][r][x] dp[l][r][x] 表示考虑区间 [ l , r ] [l,r] [l,r],其中最大值为 x x x 的时候的合法方案数。
容易注意到有转移:
d p [ l ] [ r ] [ x ] = ∑ ∣ ( r − i ) − ( i − l ) ∣ ≤ 2 ( ∑ j = 1 x d p [ l ] [ i − 1 ] [ j ] ) ( ∑ j = 1 x − 1 d p [ i + 1 ] [ r ] [ j ] ) dp[l][r][x]=\sum_{|(r-i)-(i-l)|\leq 2}(\sum_{j=1}^xdp[l][i-1][j])(\sum_{j=1}^{x-1}dp[i+1][r][j]) dp[l][r][x]=∣(r−i)−(i−l)∣≤2∑(j=1∑xdp[l][i−1][j])(j=1∑x−1dp[i+1][r][j])
转移里面有一个前缀和,考虑在这上面进行优化。
容易发现由于 x x x 的取值范围非常大,我们并不能显式维护前缀和。
可以考虑利用多项式,如果直接用生成函数的话会发现求前缀和的时候要套上一个 1 1 − x \frac{1}{1-x} 1−x1 ,感觉很烦。
考虑利用点值来做,设 F l , r ( x ) = d p [ l ] [ r ] [ x ] F_{l,r}(x)=dp[l][r][x] Fl,r(x)=dp[l][r][x],容易发现其实后面就变成了点值前缀和,也就是说我们需要支持快速求一个多项式点值前缀和的多项式,说人话就是求 G ( x ) = ∑ i = 1 x F ( i ) G(x)=\sum_{i=1}^xF(i) G(x)=∑i=1xF(i)。
则 G ( x ) = G ( x − 1 ) + F ( x ) G(x)=G(x-1)+F(x) G(x)=G(x−1)+F(x),有一个点值的转移,可以拉格朗日插值,也可以用下降幂来做。
注意到 ( x − 1 ) i ‾ = x i ‾ − i ( x − 1 ) i − 1 ‾ (x-1)^{\underline i}=x^{\underline i}-i(x-1)^{\underline{i-1}} (x−1)i=xi−i(x−1)i−1,可以得到 G ( x − 1 ) G(x-1) G(x−1) 的各项系数,进而得到 G ( x ) G(x) G(x) 的各项系数。
转移过程中需要将 [ A i , B i ] [A_i,B_i] [Ai,Bi] 外的点值变为 0,显式维护分段函数即可。
剩下的就是大力写了。复杂度 O ( 能 过 ) O(能过) O(能过),不知道有没有什么靠谱的多项式描述。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
typedef std::vector<int> Poly;
typedef std::pair<Poly,int> nd;
typedef std::vector<nd> Func;
#define fi first
#define se second
cs int N=3e2+7;
int inv[N];
Poly& operator+=(Poly &a,cs Poly &b){
if(a.size()<b.size())a.resize(b.size());
for(int re i=0;i<(int)b.size();++i)Inc(a[i],b[i]);
return a;
}Poly operator+(Poly a,cs Poly &b){return a+=b;}
Poly operator*(cs Poly &a,cs Poly &b){
int al=a.size(),bl=b.size();
Poly c(al+bl-1);static int s[N];
for(int re i=0;i<bl;++i)s[i]=b[i];
for(int re i=0;i<al;++i){
for(int re j=0;j<bl;++j)Inc(c[i+j],mul(a[i],s[j]));
for(int re j=1;j<bl;++j)Inc(s[j-1],mul(s[j],j));
}return c;
}
Poly trans(Poly a){
a.resize(a.size()+1,0);
for(int re i=a.size()-1;i;--i)
a[i]=mul(a[i-1],inv[i]);
a[0]=0;return a;
}
int calc(cs Poly &a,int x){
int res=0,mult=1;
for(int re i=0;i<(int)a.size();++i)
Inc(res,mul(a[i],mult)),Mul(mult,dec(x,i));
return res;
}
Func operator+(cs Func &a,cs Func &b){
Func c;size_t i=0,j=0;int nx=0;
while(true){
c.push_back({a[i].fi+b[j].fi,nx});
if(i+1==a.size()&&j+1==b.size())return c;
if(i+1<a.size()&&(j+1==b.size()||a[i+1].se<b[j+1].se))
nx=a[++i].se;
else nx=b[++j].se;
while(i+1<a.size()&&a[i+1].se<=nx)++i;
while(j+1<b.size()&&b[j+1].se<=nx)++j;
}
}
Func operator*(cs Func &a,cs Func &b){
Func c;size_t i=0,j=0;int nx=0;
while(true){
c.push_back({a[i].fi*b[j].fi,nx});
if(i+1==a.size()&&j+1==b.size())return c;
if(i+1<a.size()&&(j+1==b.size()||a[i+1].se<b[j+1].se))
nx=a[++i].se;
else nx=b[++j].se;
while(i+1<a.size()&&a[i+1].se<=nx)++i;
while(j+1<b.size()&&b[j+1].se<=nx)++j;
}
}
Func get(cs Func &a,int l,int r){
Func b;b.push_back({Poly(1),0});
for(size_t i=0;i<a.size();++i)
if(a[i].se<=r&&(i+1==a.size()||a[i+1].se>l))
b.push_back({a[i].fi,std::max(a[i].se,l)});
b.push_back({Poly(1),r+1});
return b;
}
Func trans(cs Func &a){
Func b;
for(size_t i=0;i<a.size();++i){
b.push_back({trans(a[i].fi),a[i].se});
if(i)b[i].fi[0]=dec(calc(b[i-1].fi,a[i].se),calc(b[i].fi,a[i].se));
}return b;
}
int n;
int A[N],B[N];
int id[N][N],tot;
Func f[N<<4];
void dfs(int l,int r){
if(id[l][r])return;
int nw=id[l][r]=++tot;
f[nw].push_back({Poly(1),0});
if(l>r){f[nw][0].fi[0]=1;return;}
for(int re i=l;i<=r;++i)
if(abs(r+l-i-i)<=2){
dfs(l,i-1);dfs(i+1,r);
Func L=f[id[l][i-1]],R=f[id[i+1][r]];
if(l<i)L=L+trans(L);if(i<r)R=trans(R);
f[nw]=f[nw]+get(L*R,A[i],B[i]);
}
}
void Main(){
scanf("%d",&n);inv[0]=inv[1]=1;
for(int re i=2;i<N;++i)
inv[i]=mul(inv[mod%i],mod-mod/i);
for(int re i=1;i<=n;++i)
scanf("%d%d",A+i,B+i);
dfs(1,n);
cout<<trans(f[1]).back().fi[0]<<"\n";
}
inline void file(){
#ifdef zxyoi
freopen("robot.in","r",stdin);
#else
freopen("robot.in","r",stdin);
freopen("robot.out","w",stdout);
#endif
}signed main(){file();Main();return 0;}