洛谷题面传送门

神仙题,放在 D1T2 可能略难了一点(

首先显然对于 P 型机器人而言,将它放在 \(i\) 之后它会走到左边第一个严格 \(>a_i\) 的位置,对于 Q 型机器人而言,将它放在 \(i\) 之后它会走到右边第一个 \(\ge a_i\) 的位置,为了避免分类讨论我们可以假定 \(a_0=a_{n+1}=\infty\)。看到这个状态我们可以设计出一个区间 \(dp\),\(dp_{l,r,x}\) 表示 \([l,r]\) 中的柱子最大值为 \(x\),并且有 \(a_{l-1}>x,a_{r+1}\ge x\) 的方案数,再设 \(sum_{l,r,x}\) 表示 \(dp_{l,r,x}\) 的前缀和,那么我们显然可以枚举最靠后的最大值的位置 \(t\),那么对于放在 \(t\) 的 P 型机器人,显然它会走到 \(l-1\),Q 型机器人会走到 \(r+1\),因此 \(dp_{l,r,x}\) 可以从 \(t\) 转移的充要条件是 \(|(t-l)-(r-t)|\le 2\) 且 \(x\in[a_l,a_r]\),因此转移是常数级别的,这样暴力做是 \(\mathcal O(n^2A)\) 的,其中 \(A=\max\{b_i\}\),可以拿到 \(35\) 分的好成绩,不过注意到对于一个区间而言,它只可能从靠中间的位置转移过来,也就是说很多 DP 状态是转移不到 \(dp_{1,n,*}\) 的,打个表可以发现有用的区间最多 \(2518\) 个,因此写个记搜,再卡卡常即可拿到 \(50\) 分。

接下来思考正解,注意到有一档部分分是 \(A_i=1,B_i=10^9\),咱们不妨来当回心理学家(大雾),思索一下,这档部分分有啥用?\(A_i=1,B_i=10^9\) 意味着所有 \(10^9\) 以内的正整数都可以成为柱子的高度,也就是说 \(x\in[a_l,a_r]\) 这个条件就没有用了,因此我们只用关心 \(|(t-l)-(r-t)|\le 2\) 这个条件即可。接下来再思索一下,\(B_i\) 这么大,出题人会让我们干嘛?显然对于 \(l=r\) 时,\(dp_{l,r,x}=1,sum_{l,r,x}=x\),而对于 \(r-l=1\) 的情况,\(dp_{l,r,x}\) 会从 \(sum_{l,l,x}\) 或 \(sum_{r,r,x}\) 转移过来,因此 \(dp_{l,r,x}\) 可以写成 \(kx\) 的形式,\(sum_{l,r,x}\) 也就可以写成 \(Ax^2+Bx\) 的形式……对!多项式!通过上面的观察可以发现,\(dp_{l,r,x}\) 是关于 \(x\) 的 \(r-l\) 次多项式,\(sum_{l,r,x}\) 是关于 \(x\) 的 \(r-l+1\) 次多项式,证明可以归纳。我们可以求出 \(sum_{l,r,x}\) 的任意 \(r-l\) 个点值,然后把这个多项式插出来即可通过 \(11,12\) 这两个测试点,由于点值连续,插值可以线性。

考虑满分做法,既然有了 \(A_i,B_i\) 的限制,并且它们范围这么大,那肯定要离散化咯,我们按照这题的套路将每个区间看作一个左开右闭的区间 \([A_i,B'_i)\),其中显然 \(B'_i=B_i+1\),然后离散化。这样一来一个数 \(i\) 就可以代表一个左开右闭的区间 \([C_i,C_{i+1})\)。按照之前的思路我们猜想在每个这样左开右闭的区间中,\(dp_{l,r,x}\) 是关于 \(x\) 的 \(r-l\) 次多项式,\(sum_{l,r,x}\) 是关于 \(x\) 的 \(r-l+1\) 次多项式,事实上这个猜想也是正确的,读者自证不难。因此考虑从小到大枚举每个区间,然后对每个 \(l,r\),求出该区间中最小的 \(\min(C_{i+1}-C_i,n+1)\) 个数的点值即可,具体实现就每次枚举一个 \(C_i\) 就开个数组 sum[l][r][x] 表示上文中所说的 \(sum_{l,r,C_i+x-1}\),dp[l][r][x] 表示上文中所说的 \(dp_{l,r,C_i+x-1}\),按照上面的套路转移 dp[l][r][x] 即可,求完所有区间的 dp 后对每个区间进行一遍插值,求出 \(sum_{l,r,x}\),在 \(C_{i+1}-1\) 处的点值,然后把它存入新的 sum[l][r][0] 即可,正确性显然,复杂度 \(\mathcal O(2518n^2)\),轻微卡常(不过对于我这个卡常菜鸡来说就得交 \(114514191981019260817998244353\) 发咯),得用一些卡常技巧,这里稍微介绍一下我的卡常技巧:

  • 对区间 \([l,r]\) 进行插值的时候,可以只用前 \(r-l+1\) 个点值插值,不用插 \(n+1\) 个点值。
  • 可以特判掉 \(C_{i+1}-C_i\le n\) 的情况,这样 \(C_{i+1}-1\) 处的点值我们在 DP 的时候已经求出来了
  • 插值不必按部就班地求出前缀后缀积,由于我们已经特判掉了 \(C_{i+1}-C_i\le n\) 的情况,因此一定有 \(C_i+j-1\ne C_{i+1},j\in[1,n+1]\),此时只要预处理一遍每个 \(C_{i}+j-1\) 的逆元然后那全部 \(C_i+j-1\) 的乘积乘上对应的逆元即可。
const int MAXN=300;
const int MOD=1e9+7;
const int MAXS=2520;
void add(int &x,int y){((x+=y)>=MOD)&&(x-=MOD);}
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int n,a[MAXN+5],b[MAXN+5],key[MAXN*2+5],uni[MAXN*2+5],num=0;
int id[MAXN+5][MAXN+5],itvl_n=0;pii itvls[MAXS+5];
void find_itvl(int l,int r){
if(id[l][r]) return;id[l][r]=++itvl_n;
itvls[itvl_n]=mp(l,r);if(l>r) return;
for(int i=l;i<=r;i++) if(abs((i-l)-(r-i))<=2)
find_itvl(l,i-1),find_itvl(i+1,r);
}
int dp[MAXS+5][MAXN+5];bool vis[MAXN+5][MAXN+5];
void work(int l,int r,int len,int itv){
if(l>r){
for(int i=0;i<=len;i++) dp[id[l][r]][i]=1;
return;
} if(vis[l][r]) return;vis[l][r]=1;
for(int i=1;i<=len;i++) dp[id[l][r]][i]=0;
for(int x=l;x<=r;x++) if(abs((x-l)-(r-x))<=2) if(a[x]<=itv&&itv<b[x]){
work(l,x-1,len,itv);work(x+1,r,len,itv);
for(int i=1;i<=len;i++){
dp[id[l][r]][i]=(dp[id[l][r]][i]+1ll*
dp[id[l][x-1]][i]*dp[id[x+1][r]][i-1])%MOD;
}
}
for(int k=1;k<=len;k++) add(dp[id[l][r]][k],dp[id[l][r]][k-1]);
}
int iv[MAXN+5],ifac[MAXN+5];
void init_fac(int n){
for(int i=(ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
}
void getval(int l,int r){
if(r-l+1<=n+1){
for(int i=1;i<=itvl_n;i++) dp[i][0]=dp[i][r-l+1];
return;
} for(int i=1;i<=n+1;i++) iv[i]=qpow(r-(l+i-1),MOD-2);
for(int i=1;i<=itvl_n;i++){
if(itvls[i].fi>itvls[i].se) continue;
int len=itvls[i].se-itvls[i].fi+1,tot=1;
for(int j=1;j<=len+1;j++) tot=1ll*tot*(r-(l+j-1))%MOD;
dp[i][0]=0;
for(int j=1;j<=len+1;j++){
int mul=1ll*ifac[j-1]*ifac[len+1-j]%MOD*tot%MOD*iv[j]%MOD;
if((len+1-j)&1) mul=MOD-mul;
dp[i][0]=(dp[i][0]+1ll*mul*dp[i][j])%MOD;
}
}
}
int main(){
// freopen("robot.in","r",stdin);
// freopen("robot.out","w",stdout);
scanf("%d",&n);init_fac(n+3);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);++b[i];
key[i*2-1]=a[i];key[i*2]=b[i];
} sort(key+1,key+(n<<1)+1);
for(int i=1;i<=n<<1;i++) if(key[i]^key[i-1])
uni[++num]=key[i];
for(int i=1;i<=n;i++){
a[i]=lower_bound(uni+1,uni+num+1,a[i])-uni;
b[i]=lower_bound(uni+1,uni+num+1,b[i])-uni;
} find_itvl(1,n);
for(int i=1;i<num;i++){
// printf("%d %d\n",uni[i],uni[i+1]-1);
memset(vis,0,sizeof(vis));
for(int l=1;l<=n;l++) for(int r=l-1;r<=n;r++)
if(id[l][r]) work(l,r,min(uni[i+1]-uni[i],n+1),i);
getval(uni[i],uni[i+1]-1);
// for(int j=1;j<=itvl_n;j++) printf("%d %d %d\n",i,j,dp[j][0]);
} printf("%d\n",dp[id[1][n]][0]);
return 0;
}

洛谷 P5469 - [NOI2019] 机器人(区间 dp+拉格朗日插值)的更多相关文章

  1. 洛谷P2470 [SCOI2007]压缩(区间dp)

    题意 题目链接 Sol 神仙题Orz 考虑区间dp,如果我们只设\(f[l][r]\)表示\(s_{lr}\)被压缩的最小长度,而不去关心内部\(M\)分布的话,可能在转移的时候转移出非法状态 因此考 ...

  2. 洛谷P1018乘积最大——区间DP

    题目:https://www.luogu.org/problemnew/show/P1018 区间DP+高精,注意初始化和转移的细节. 代码如下: #include<iostream> # ...

  3. 洛谷P1220关路灯——区间DP

    题目:https://www.luogu.org/problemnew/show/P1220 区间DP. 代码如下: #include<iostream> #include<cstd ...

  4. 洛谷P1040 加分二叉树(区间dp)

    P1040 加分二叉树 题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di, ...

  5. 洛谷 P1080 石子合并 ( 区间DP )

    题意 : 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分.试设计出1个算法,计算出将N堆石子合并成1堆 ...

  6. 洛谷$P1864\ [NOI2009]$二叉查找树 区间$dp$

    正解:区间$dp$ 解题报告: 传送门$QwQ$ 首先根据二叉查找树的定义可知,数据确定了,这棵树的中序遍历就已经改变了,唯一能改变的就是通过改变权值从而改变结点的深度. 发现这里权值的值没有意义,所 ...

  7. 洛谷P1063能量项链(区间dp)

    题目描述: 给定一串序列x[],其中的每一个Xi看作看作一颗珠子,每个珠子包含两个参数,head和tail,前一颗的tail值是后一个的head值,珠子呈现环形(是一条项链),所以最后一颗的tail是 ...

  8. 洛谷 P1043 数字游戏 区间DP

    题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n个),你要按顺序将其分 ...

  9. 洛谷 P1220 关路灯 区间DP

    题目描述 某一村庄在一条路线上安装了 n 盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. 为了 ...

随机推荐

  1. 2.3 Core Building Blocks 核心构件

    Core Building Blocks 核心构件 DDD mostly focuses on the Domain & Application Layers and ignores the ...

  2. Spring DeferredResult 异步请求

    Spring DeferredResult 异步请求 一.背景 二.分析 三.实现要求 四.后端代码实现 五.运行结果 1.超时操作 2.正常操作 六.DeferredResult运行原理 六.注意事 ...

  3. 2021NOI同步赛

    \(NOI\) 网上同步赛 明白了身为菜鸡的自己和普通人的差距 DAY1 \(T1\) 轻重边 [题目描述] 小 W 有一棵 \(n\) 个结点的树,树上的每一条边可能是轻边或者重边.接下来你需要对树 ...

  4. Less3

    继续第三关的学习 1.根据第一关的记录,我们判断出是什么注入 id=1' and '1'='1 id=1' and '1'='2 返回不同,所以存在字符型的注入 2. 这时候我们再用正常的报错猜解准备 ...

  5. Python:Ubuntu上使用pip安装opencv-python出现错误

    Ubuntu 18.04 上 使用 pip 安装 opencv-python,出现的错误如下: 1 ~$: pip install opencv-python -i https://pypi.tuna ...

  6. 结束的NULL

    最近同学叫我帮忙看个问题,为啥这个循环没有退出, 代码如下,原本是想拿到最后的NULL指针就可以结束循环 #include <stdio.h> #include <stdlib.h& ...

  7. hdu 2473 Junk-Mail Filter(并查集)

    题意: N个邮件需要鉴别. 两种操作: 1. M X Y:X和Y是同一种邮件 2.S X:X被误判(意味着X要被它从属的那个集合"踢出去"而所有其它的邮件的关系保持不变) 问最后总 ...

  8. 2021 ICPC 江西省赛总结

      比赛链接:https://ac.nowcoder.com/acm/contest/21592   大三的第一场正式赛,之前的几次网络赛和选拔赛都有雄哥坐镇,所以并没有觉得很慌毕竟校排只取每个学校成 ...

  9. RocketMQ源码详解 | Broker篇 · 其三:CommitLog、索引、消费队列

    概述 上一章中,已经介绍了 Broker 的文件系统的各个层次与部分细节,本章将继续了解在逻辑存储层的三个文件 CommitLog.IndexFile.ConsumerQueue 的一些细节.文章最后 ...

  10. SpringBoot之MultipartFile文件上传(6)

    1.静态文件 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...