机器人
题解
首先对于这道题,我们是比较容易得到一个
O
(
n
2
B
)
O\left(n^2B\right)
O(n2B)的
d
p
dp
dp做法的。
我们定义
d
p
l
,
r
,
k
dp_{l,r,k}
dpl,r,k表示对于区间
[
l
,
r
]
[l,r]
[l,r],其中最大值为
k
k
k,且机械人不能走出区间
[
l
,
r
]
[l,r]
[l,r]的方案数。
其中转移我们可以考虑枚举最后一个大小为
k
k
k的机械人在哪里,显然,它前面的机械人往后走都是不可能超过它的,它后面的也不可能走到它前面去,这样整个区间就被分成两半了,可以区间
d
p
dp
dp。
由于对于任意一个区间,为了满足两边距离差的绝对值不超过
2
2
2,可以放机械人的位置只会有常数个。
只需要再同时维护一个前缀和,就可以
O
(
n
2
B
)
O\left(n^2B\right)
O(n2B)了。
但有用的区间真的有
O
(
n
2
)
O(n^2)
O(n2)吗?题目奇怪的性质好像会使绝大多数区间都不会贡献到答案。
经代码验证,真正有用的区间不会超过
3000
3000
3000个,这样就大大提升了我们代码运行的效率,基本已经可以过前
50
50
50分。
关注之后
A
=
1
,
B
=
1
0
9
A=1,B=10^9
A=1,B=109的部分分。
我们不妨理性猜测这是一个以
[
A
,
B
]
[A,B]
[A,B]为值域的多项式,考虑归纳证明。
显然,对于
i
=
j
i=j
i=j的情况,
d
p
i
,
j
(
x
)
=
1
dp_{i,j}(x)=1
dpi,j(x)=1。
再将它做个前缀和,多项式的前缀和不也是多项式?下面用
d
p
′
dp'
dp′表示做了前缀和了的
d
p
dp
dp。
再来看
d
p
l
,
r
dp_{l,r}
dpl,r的转移式,
d
p
l
,
r
(
x
)
=
∑
m
i
d
[
∣
(
r
−
m
i
d
)
−
(
m
i
d
−
l
)
∣
⩽
2
]
d
p
l
,
m
i
d
−
1
′
(
x
)
d
p
m
i
d
+
1
,
r
′
(
x
)
dp_{l,r}(x)=\sum_{mid}[|(r-mid)-(mid-l)|\leqslant 2]dp'_{l,mid-1}(x)dp'_{mid+1,r}(x)
dpl,r(x)=∑mid[∣(r−mid)−(mid−l)∣⩽2]dpl,mid−1′(x)dpmid+1,r′(x),这不就是把递归到两边的多项式乘起来吗?这不还是一个多项式?
于是我们就完成了证明。
同时通过上面的递归过程,我们可以知道
d
p
l
,
r
dp_{l,r}
dpl,r是个
r
−
l
r-l
r−l次的多项式,
d
p
′
dp'
dp′自然是
r
−
l
+
1
r-l+1
r−l+1次的多项式。
然后就可以拉格朗日插值了。
有了上面的经验,自然可以想到对于之后的点我们将
[
A
,
B
]
[A,B]
[A,B]进行离散化,并在离散化后的每个连续区间内,
d
p
l
,
r
dp_{l,r}
dpl,r都是一个多项式。
这是显然的,毕竟在这区间外的位置的答案对里面的贡献都只是一个常数,并不会影响它是不是一个多项式。
那么我们只需要对于离散化后得到的值域区间依次对整个序列区间
d
p
dp
dp求解,并在之后保留下来上一次求解得到的前缀和以辅助下一次
d
p
dp
dp求解,就能够很快地得到整个区间的答案了。
另外,如果插值的时候当前值域区间不足
r
−
l
+
2
r-l+2
r−l+2个,我们可以只插值域区间长度这么多的值,毕竟这样就可以应付我们所有的询问了。
记 m m m为有用区间长度的平方和(显然是比较小的),最后总时间复杂度为 O ( m n ) O\left(mn\right) O(mn)。
源码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
#define MAXN 4005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int mo=1e9+7;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=15;
const LL INF=0x3f3f3f3f3f3f3f3f;
const double Pi=acos(-1.0);
const double eps=1e-9;
const int lim=1000000;
const int orG=3,ivG=332748118;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,a[305],b[305],d[605],totd,ls[MAXN],rs[MAXN];
int g[MAXN][605],id[305][305],idx;pii cp[305];bool vis[MAXN][605];
struct poly{
int m,a[305];poly(){m=0;}
void clear(){for(int i=0;i<=m;i++)a[i]=0;}
poly operator + (const poly &rhs)const{
poly res;res.m=max(m,rhs.m);res.clear();
for(int i=0;i<=m;i++)res.a[i]=a[i];
for(int i=0;i<=rhs.m;i++)Add(res.a[i],rhs.a[i],mo);
return res;
}
poly operator * (const int &rhs)const{
poly res;res.m=m;res.clear();
for(int i=0;i<=m;i++)res.a[i]=1ll*rhs*a[i]%mo;
return res;
}
poly operator ^ (const int &rhs)const{
poly res;res.m=m+1;res.clear();
for(int i=0;i<=m;i++)res.a[i]=mo-1ll*rhs*a[i]%mo;
for(int i=0;i<=m;i++)Add(res.a[i+1],a[i],mo);
return res;
}
int ask(int x){
int res=0,now=1;
for(int i=0;i<=m;i++,now=1ll*x*now%mo)
Add(res,1ll*a[i]*now%mo,mo);
return res;
}
}dp[MAXN],TP;
void init(int l,int r){
if(id[l][r])return ;
id[l][r]=++idx;dp[idx].m=dp[idx].a[0]=0;
if(l==r)return ;int rt=id[l][r];
for(int i=l;i<=r;i++)
if(Fabs((i-l)-(r-i))<=2){
if(l<i)init(l,i-1);
if(r>i)init(i+1,r);
if(!ls[rt])ls[rt]=i;rs[rt]=i;
}
}
void sakura(int l,int r,int p){
int rt=id[l][r];if(vis[rt][p])return ;vis[rt][p]=1;
if(l==r){
if(a[l]>p)dp[rt].m=0,dp[rt].a[0]=0,g[rt][p]=0;
else if(a[l]<=p&&p<b[l])
dp[rt].m=1,dp[rt].a[1]=1,dp[rt].a[0]=mo-d[a[l]]+1,g[rt][p]=d[p+1]-d[a[l]];
else dp[rt].m=0,dp[rt].a[0]=d[b[l]]-d[a[l]],g[rt][p]=d[b[l]]-d[a[l]];
return ;
}
for(int i=ls[rt];i<=rs[rt];i++){
if(l<i)sakura(l,i-1,p);
if(r>i)sakura(i+1,r,p);
}
int len=min(d[p+1]-d[p],r-l+2),summ=g[rt][p-1];
for(int i=1,now=d[p];i<=len;i++,now++){
for(int j=ls[rt],tmp=1;j<=rs[rt];j++){
if(d[a[j]]>now||now>=d[b[j]])continue;
if(l<j)tmp=1ll*tmp*dp[id[l][j-1]].ask(now)%mo;
if(j<r)tmp=(now==d[p]?1ll*tmp*g[id[j+1][r]][p-1]:1ll*tmp*dp[id[j+1][r]].ask(now-1))%mo;
Add(summ,tmp,mo);tmp=1;
}
cp[i]=mkpr(summ,now);
}
dp[rt].m=0;dp[rt].clear();dp[rt].a[0]=cp[1].fir;
TP.m=1;TP.clear();TP.a[1]=1;TP.a[0]=mo-cp[1].sec;
for(int i=2;i<=len;i++){
int tp=add(cp[i].fir,mo-dp[rt].ask(cp[i].sec),mo);
if(tp)tp=1ll*tp*qkpow(TP.ask(cp[i].sec),mo-2,mo)%mo;
if(tp)dp[rt]=dp[rt]+TP*tp;TP=TP^cp[i].sec;
}
g[rt][p]=dp[rt].ask(d[p+1]-1);bool flag=0;
}
int main(){
read(n);init(1,n);
for(int i=1;i<=n;i++)
read(a[i]),read(b[i]),
d[++totd]=a[i],d[++totd]=b[i]+1;
sort(d+1,d+totd+1);totd=unique(d+1,d+totd+1)-d-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(d+1,d+totd+1,a[i])-d,
b[i]=lower_bound(d+1,d+totd+1,b[i]+1)-d;
for(int i=1;i<totd;i++)sakura(1,n,i);
printf("%d\n",g[id[1][n]][totd-1]);
return 0;
}