【LOJ #3157】「NOI2019」机器人(区间DP / 下降幂多项式)

传送门

莫名就跑到了 l o j   r k 1 ? loj\ rk1? loj rk1?
理解不能


首先可以列出一个显然的 D P DP DP
f l , r , x f_{l,r,x} fl,r,x表示 [ l , r ] [l,r] [l,r]最大值为 x x x的方案数
那么显然有
f l , r , x = ∑ k , ∣ r − k + l − k ∣ ≤ 2 ( ∑ y ≤ x f l , k − 1 , x ) ( ∑ y < x f k + 1 , r , x ) f_{l,r,x}=\sum_{k,|r-k+l-k|\le2}(\sum_{y\le x}f_{l,k-1,x})(\sum_{yfl,r,x=k,rk+lk2(yxfl,k1,x)(y<xfk+1,r,x)

考虑如果对于 A , B A,B A,B无限制时
可以归纳的得到 f l , r f_{l,r} fl,r是关于 x x x r − l + 1 r-l+1 rl+1次多项式
由于 x x x太大考虑用系数表示
则转移时前缀和实际上是一个离散积分
就是求 y ≤ x y\le x yx f l , r ( y ) f_{l,r}(y) fl,r(y) x x x表示的和
如果直接用普通多项式求并不优秀

考虑用下降幂多项式
由于有 x j ‾ − ( x − 1 ) j ‾ = j ( x − 1 ) j − 1 ‾ x^{\underline j}-(x-1)^{\underline j}=j(x-1)^{\underline {j-1}} xj(x1)j=j(x1)j1
x i ‾ = ( x + 1 ) i + 1 ‾ − x i + 1 ‾ i + 1 x^{\underline i}=\frac{(x+1)^{\underline{i+1}}-x^{\underline {i+1}}}{i+1} xi=i+1(x+1)i+1xi+1
那么 ∑ x = 1 n x i ‾ = ∑ i = 1 n ( x + 1 ) i + 1 ‾ − x i + 1 ‾ i + 1 \sum_{x=1}^nx^{\underline i}=\frac{\sum_{i=1}^n{(x+1)}^{\underline{i+1}}-x^{\underline {i+1}}}{i+1} x=1nxi=i+1i=1n(x+1)i+1xi+1
= ( n + 1 ) i + 1 ‾ − [ i = 1 ] i + 1 =\frac{(n+1)^{\underline{i+1}}-[i=1]}{i+1} =i+1(n+1)i+1[i=1]
则例如 ∑ i = 1 x − 1 ∑ j a j i j ‾ = ∑ j a j ∑ i = 1 x − 1 i j ‾ = ∑ j a j x j + 1 ‾ j + 1 \sum_{i=1}^{x-1}\sum_{j}a_ji^{\underline j}=\sum_ja_j\sum_{i=1}^{x-1}i^{\underline j}=\sum_ja_j\frac{x^{\underline {j+1}}}{j+1} i=1x1jajij=jaji=1x1ij=jajj+1xj+1

于是对于下降幂多项式可以做到 O ( n ) O(n) O(n)求前缀和
那么还需要做的就是对于下降幂多项式相加相乘
至于相乘
可以 m t t mtt mtt做到 O ( n l o g n ) O(nlogn) O(nlogn)
但是没有必要
考虑怎么做 O ( n 2 ) O(n^2) O(n2)的乘法
对于 ∑ i a i x i ‾ ∗ ∑ i b i x i ‾ \sum_i a_ix^{\underline i}*\sum_ib_ix^{\underline i} iaixiibixi
那么对于左边的 x i ‾ x^{\underline i} xi,右边应该拿 ( x − i ) j ‾ (x-i)^{\underline j} (xi)j来乘
又有 x j ‾ − ( x − 1 ) j ‾ = j ( x − 1 ) j − 1 ‾ x^{\underline j}-(x-1)^{\underline j}=j(x-1)^{\underline {j-1}} xj(x1)j=j(x1)j1
于是可以每次 O ( n ) O(n) O(n)的将 ∑ i b i x i ‾ \sum_ib_ix^{\underline i} ibixi变成 ∑ i b i ( x − 1 ) i ‾ \sum_ib_i(x-1)^{\underline i} ibi(x1)i

现在考虑有 A , B A,B A,B的限制
那么可以离散化成 O ( n ) O(n) O(n)个区间
每个区间内部的多项式是一样的
于是变成维护分段下降幂多项式

其他处理是一样的
记忆化搜索实现这个 D P DP DP
复杂度为 O ( n ∑ l , r [ 区 间 l , r 合 法 ] ( r − l + 1 ) 2 ) O(n\sum_{l,r}[区间l,r合法](r-l+1)^2) O(nl,r[l,r](rl+1)2)
据说分析出来就是 O ( n 3 ) O(n^3) O(n3)
确实跑的飞快

#include
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline ll readll(){
    char ch=gc();
    ll res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	return top;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Dec(int &a,int b){a-=b,a+=a>>31&mod;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){if(a==0&&b==0)return 0;for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(int x){return (x<0)?x+mod:x;}
cs int N=305;
int iv[N];
inline void init_inv(){
	iv[0]=iv[1]=1;
	for(int i=2;i<N;i++)iv[i]=mul(mod-mod/i,iv[mod%i]);
}
typedef vector<int> poly;
inline int F(cs poly &f,int x){
	int res=0;
	for(int i=0,mt=1;i<f.size();Mul(mt,x-i),i++)Add(res,mul(f[i],mt));
	return res;
}
inline poly operator +(poly a,poly b){
	a.resize(max(a.size(),b.size()));
	for(int i=0;i<b.size();i++)Add(a[i],b[i]);
	return a;
}
inline poly operator *(poly a,poly b){
	int deg=a.size()+b.size()-1;
	poly c(deg,0);
	for(int i=0;i<a.size();i++){
		for(int j=0;j<b.size();j++)Add(c[i+j],mul(a[i],b[j]));
		for(int j=1;j<b.size();j++)Add(b[j-1],mul(b[j],j));
	}
	return c;
}
inline poly integ(poly a){
	a.pb(0);
	for(int i=a.size()-1;i;i--)a[i]=mul(a[i-1],iv[i]);
	a[0]=0;return a;
}
typedef pair<poly,int> pi;
typedef vector<pi> Poly;

inline Poly operator +(cs Poly &a,cs Poly &b){
	Poly c;int i=0,j=0,lim=0;
	while(0721){
		c.pb(pi(a[i].fi+b[j].fi,lim));
		if(i+1==a.size()&&j+1==b.size())break;
		if(i+1<a.size()&&(j+1==b.size()||a[i+1].se<b[j+1].se))
		lim=a[++i].se;else lim=b[++j].se;
		if(i+1<a.size()&&a[i+1].se<=lim)i++;
		if(j+1<b.size()&&b[j+1].se<=lim)j++;
	}
	return c;
}
inline Poly operator *(cs Poly &a,cs Poly &b){
	Poly c;int i=0,j=0,lim=0;
	while(0721){
		c.pb(pi(a[i].fi*b[j].fi,lim));
		if(i+1==a.size()&&j+1==b.size())break;
		if(i+1<a.size()&&(j+1==b.size()||a[i+1].se<b[j+1].se))
		lim=a[++i].se;else lim=b[++j].se;
		if(i+1<a.size()&&a[i+1].se<=lim)i++;
		if(j+1<b.size()&&b[j+1].se<=lim)j++;
	}
	return c;	
}
inline Poly cut(cs Poly &a,int l,int r){
	Poly b;b.pb(pi(poly(1),0));
	for(int i=0;i<a.size();i++){
		if(a[i].se<=r&&(i+1==a.size()||a[i+1].se>l))
		b.pb(pi(a[i].fi,max(l,a[i].se)));
	}
	b.pb(pi(poly(1),r+1));
	return b;
}
inline Poly integ(cs Poly &a){
	Poly b;
	for(int i=0;i<a.size();i++){
		b.pb(pi(integ(a[i].fi),a[i].se));
		if(i)b[i].fi[0]=dec(F(b[i-1].fi,a[i].se),F(b[i].fi,a[i].se));
	}return b;
}
Poly f[2505];
int n,id[N][N],tot,L[N],R[N];
void dfs(int l,int r){
	if(id[l][r])return;
	id[l][r]=++tot;
	int u=id[l][r];
	f[u].pb(pi(poly(1,0),0));
	if(l>r){f[u][0].fi[0]=1;return;}
	for(int i=l;i<=r;i++)if(abs(r-i-(i-l))<=2){
		dfs(l,i-1),dfs(i+1,r);
		Poly vl=f[id[l][i-1]],vr=f[id[i+1][r]];
		if(l<i)vl=vl+integ(vl);
		if(i<r)vr=integ(vr);
		f[u]=f[u]+cut(vl*vr,L[i],R[i]);
	}
}
int main(){
	freopen("robot.in","r",stdin);
	freopen("robot.out","w",stdout);
	n=read();
	init_inv();
	for(int i=1;i<=n;i++)L[i]=read(),R[i]=read();
	dfs(1,n);
	cout<<integ(f[id[1][n]]).back().fi[0]<<'\n';
	return 0;
}

你可能感兴趣的:(区间dp,多项式)