[NOI2019]机器人
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOI2019]机器人相关的知识,希望对你有一定的参考价值。
机器人
题解
首先对于这道题,我们是比较容易得到一个
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少儿编程 电子学会机器人等级考试一级真题解析判断题2019-3