P5469 [NOI2019] 机器人 洛谷黑题题解

2024-01-25 02:36

本文主要是介绍P5469 [NOI2019] 机器人 洛谷黑题题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[NOI2019] 机器人

题目背景

时限 3 秒,内存 512MB

题目描述

小 R 喜欢研究机器人。

最近,小 R 新研制出了两种机器人,分别是 P 型机器人和 Q 型机器人。现在他要测试这两种机器人的移动能力,测试在从左到右排成一排的 n n n 个柱子上进行,柱子用 1 − n 1 - n 1n 依次编号, i i i 号柱子的高度为一个正整数 h i h_i hi。机器人只能在相邻柱子间移动,即:若机器人当前在 i i i 号柱子上,它只能尝试移动到 i − 1 i - 1 i1 号和 i + 1 i + 1 i+1 号柱子上。

每次测试,小 R 会选取一个起点 s s s,并将两种机器人均放置在 s s s 号柱子上。随后它们会按自己的规则移动。

P 型机器人会一直向左移动,但它无法移动到比起点 s s s 更高的柱子上。更具体地,P 型机器人在 l ( l ≤ s ) l (l \leq s) l(ls) 号柱子停止移动,当且仅当下列两个条件均成立:

  • l = 1 l = 1 l=1 h l − 1 > h s h_{l-1} > hs hl1>hs

  • 对于满足 l ≤ j ≤ s l \leq j \leq s ljs j j j,有 h j ≤ h s h_j \leq h_s hjhs

Q 型机器人会一直向右移动,但它只能移动到比起点 s s s 更低的柱子上。更具体地,Q 型机器人在 r ( r ≥ s ) r (r \geq s) r(rs) 号柱子停止移动,当且仅当下列两个条件均成立:

  • r = n r = n r=n h r + 1 ≥ h s h_{r+1} \geq h_s hr+1hs

  • 对于满足 s < j ≤ r s < j \leq r s<jr j j j,有 h j < h s h_j < h_s hj<hs

现在,小 R 可以设置每根柱子的高度, i i i 号柱子可选择的高度范围为 [ A i , B i ] [A_i, B_i] [Ai,Bi],即 A i ≤ h i ≤ B i A_i \leq h_i \leq B_i AihiBi。小 R 希望无论测试的起点 s s s 选在哪里,两种机器人移动过的柱子数量的差的绝对值都小于等于 2 2 2。他想知道有多少种柱子高度的设置方案满足要求,小 R 认为两种方案不同当且仅当存在一个 k k k,使得两种方案中 k k k 号柱子的高度不同。请你告诉他满足要求的方案数模 1 0 9 + 7 10^9 + 7 109+7 后的结果。

输入格式

第一行一个正整数 n n n,表示柱子的数量。

接下来 n n n 行,第 i i i 行两个正整数 A i , B i A_i, B_i Ai,Bi,分别表示 i i i 号柱子的最小和最大高度。

输出格式

仅一行一个整数,表示答案模 1 0 9 + 7 10^9 + 7 109+7 的值。

样例 #1

样例输入 #1

5
3 3
3 3
3 4
2 2
3 3

样例输出 #1

1

提示

更多样例

您可以通过附加文件获得更多样例。

样例 2

见附加文件的 robot/robot2.inrobot/robot2.ans

样例 3

见附加文件的 robot/robot3.inrobot/robot3.ans

样例 4

见附加文件的 robot/robot4.inrobot/robot4.ans

样例 1 解释

柱子高度共两种情况:

  • 高度为:3 2 3 2 3。此时若起点设置在 5 5 5P 型机器人将停在 1 1 1 号柱子,共移动 4 4 4 个柱子。Q 型机器人停在 5 5 5 号柱子,共移动 0 0 0 个柱子,不符合条件。

  • 高度为:3 2 4 2 3。此时无论起点选在哪,都满足条件,具体见下表:

起点编号P 型机器人Q 型机器人
1 1 1停在 1 1 1 号柱子,移动过 0 0 0停在 2 2 2 号柱子,移动过 1 1 1
2 2 2停在 2 2 2 号柱子,移动过 0 0 0停在 2 2 2 号柱子,移动过 0 0 0
3 3 3停在 1 1 1 号柱子,移动过 2 2 2停在 5 5 5 号柱子,移动过 2 2 2
4 4 4停在 4 4 4 号柱子,移动过 0 0 0停在 4 4 4 号柱子,移动过 0 0 0
5 5 5停在 4 4 4 号柱子,移动过 1 1 1停在 5 5 5 号柱子,移动过 0 0 0

数据范围

对于所有测试数据: 1 ≤ n ≤ 300 1 \leq n \leq 300 1n300 , 1 ≤ A i ≤ B i ≤ 1 0 9 1 \leq A_i \leq B_i \leq 10^9 1AiBi109

每个测试点的具体限制见下表:

测试点编号 n ≤ n\le n特殊性质
1 , 2 1,2 1,2 7 7 7 A i = B i , B i ≤ 7 A_i=B_i,B_i\le 7 Ai=Bi,Bi7
3 , 4 3,4 3,4 7 7 7 B i ≤ 7 B_i\le 7 Bi7
5 , 6 , 7 5,6,7 5,6,7 50 50 50 B i ≤ 100 B_i\le 100 Bi100
8 , 9 , 10 8,9,10 8,9,10 300 300 300 B i ≤ 1 0 4 B_i\le 10^4 Bi104
11 , 12 11,12 11,12 50 50 50 A i = 1 , B i = 1 0 9 A_i=1,B_i=10^9 Ai=1,Bi=109
13 , 14 , 15 13,14,15 13,14,15 50 50 50
16 , 17 16,17 16,17 150 150 150
18 , 19 18,19 18,19 200 200 200
20 20 20 300 300 300
#include<bits/stdc++.h>
using namespace std;
inline int read()
{int res=0; bool f=0;char ch=getchar();while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();while(isdigit(ch)) res=res*10+(ch^'0'),ch=getchar();return f?-res:res;
}
const int N=605,mod=1000000007;
struct node{int l,r;bool operator<(const node &t)const{return r-l<t.r-t.l;}
}p[3030];
int n,tot,id[N][N],a[N],b[N];
int fac[N],inv[N];
inline int qmi(int x,int y)
{int res=1;while(y){if(y&1) res=1ll*res*x%mod;x=1ll*x*x%mod;y>>=1;}return res;
}
void init(int n)//预处理阶乘和逆元
{fac[0]=inv[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;inv[n]=qmi(fac[n],mod-2);for(int i=n-1;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
inline void add(int &x,int y)
{x+=y;if(x>=mod) x-=mod;
}
void dfs(int l,int r)//预处理合法区间
{if(id[l][r]||l>r) return;id[l][r]=++tot;p[tot]={l,r};for(int i=l;i<=r;i++)//枚举分界线   if(abs((i-l)-(r-i))<=2)dfs(l,i-1),dfs(i+1,r);
}
int num[N],cnt;
void read_and_change()
{for(int i=1;i<=n;i++){num[++cnt]=a[i]=read();num[++cnt]=b[i]=read()+1;//左闭右开 后面方便}sort(num+1,num+cnt+1);cnt=unique(num+1,num+cnt+1)-num-1;for(int i=1;i<=n;i++){a[i]=lower_bound(num+1,num+cnt+1,a[i])-num;b[i]=lower_bound(num+1,num+cnt+1,b[i])-num;}
}
int f[3030][N],pre[N],suf[N];
inline void lag(int l,int r,int len)
{if(len<=n+1) {for(int i=1;i<=tot;i++) f[i][0]=f[i][len];return;}for(int i=1;i<=tot;i++) f[i][0]=0;pre[0]=suf[n+2]=1;//pre、suf就是把带入len之后的式子的分子前后缀前for(int i=1;i<=n+1;i++) pre[i]=1ll*pre[i-1]*((len-i+mod)%mod)%mod;for(int i=n+1;i>=1;i--) suf[i]=1ll*suf[i+1]*((len-i+mod)%mod)%mod;for(int i=1;i<=n+1;i++){int val=1ll*pre[i-1]*suf[i+1]%mod/*分子*/*inv[n+1-i]%mod*inv[i-1]%mod/*分母*/*(((n+1-i)&1)?mod-1:1)%mod/*分母的符号*/;for(int j=1;j<=tot;j++)add(f[j][0],1ll*val*f[j][i]%mod);}
}
int main()
{n=read();init(n+5);dfs(1,n); sort(p+1,p+tot+1);read_and_change();//读入并离散化for(int i=0;i<=n+1;i++) f[0][i]=1;for(int t=1;t<cnt;t++){int len=min(n+1,num[t+1]-num[t]);for(int i=1;i<=tot;i++){int l=p[i].l,r=p[i].r;for(int j=l;j<=r;j++)if(abs((j-l)-(r-j))<=2&&t>=a[j]&&t<b[j])for(int k=1;k<=len;k++)add(f[id[l][r]][k],1ll*f[id[l][j-1]][k]*f[id[j+1][r]][k-1]%mod);//最初的DP中的“最大值”就是最靠右的最大值,所以右区间的最大值一定比k小(j位置是k)for(int k=1;k<=len;k++) add(f[id[l][r]][k],f[id[l][r]][k-1]);//前缀和优化}lag(num[t],num[t+1],num[t+1]-num[t]);for(int i=1;i<=tot;i++)for(int j=1;j<=len;j++)f[i][j]=0;}printf("%d\n",f[id[1][n]][0]);return 0;
}
#include<bits/stdc++.h>
#define il inline
#define re register
#define b_s basic_string
#define For(i,a,b) for(re int i=(a);i<=(b);++i)
#define foR(i,a,b) for(re int i=(a);i>=(b);--i)
#define uint unsigned int
#define ll long long
#define ull unsigned long long
using namespace std;
il void rd(int &x){x=0;bool f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=0;ch=getchar();}while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}x=f?x:-x;return;
}const int maxn=307,maxm=2608;//maxm是最大区间数
const ll mod=1e9+7;
int n;
int A[307],B[307];il ll qpow(ll x,ll t){int ret=1;while(t){if(t&1) ret=ret*x%mod;x=x*x%mod;t>>=1;}return ret;
}
il int inv(int x){return qpow(x,mod-2);}int id[maxn][maxn],toti;//0就是区间不存在 
il bool ok(int l,int mid,int r){return abs((mid-l)-(r-mid))<=2;}
il void sinte(int l,int r){//本函数是用于区间初始化的递归函数。 if(id[l][r]) return;id[l][r]=++toti;if(l>=r) return;For(mid,l,r)if(ok(l,mid,r))sinte(l,mid-1),sinte(mid+1,r);
}int key[607],totk;
ll invfact[307];
int usek;
il void init(){//本函数负责读入,并参与到区间初始化和拉插初始化中。rd(n); usek=n+1;For(i,1,n){rd(A[i],B[i]);key[++totk]=A[i],key[++totk]=B[i]+1;//A[i]是到这里就变,B[i]是下一个才变。我们希望key里面存的每一个都是变的点,这样一来我们就可以取出左闭右开区间。 }sort(key+1,key+1+totk);totk=unique(key+1,key+1+totk)-key-1;//去重后结果。 sinte(1,n);invfact[0]=1;For(i,1,usek) invfact[i]=invfact[i-1]*inv(i)%mod;
}int L,R,S,N;//当前考虑的闭区间的左右端点,该区间长度,计划中要dp出的长度 
ll dp[maxn][maxm]; bitset<maxm> vis;//该区间是否在本轮dp中访问过 
//dp[mx][now]表示第now个区间的最大值不超过mx的方案数。定义tp[mx][now]表示恰好为的方案数。
//对于非初始区间(r>l): 
//因为我们在dfs内实际上是逐个区间转移,我们可以先这样转移:dp(实为tp)[mx][now]=∑mid [ (∑i=0~mx tp[i][left])*(∑i=0~mx-1 tp[i][right]) ]=∑mid (dp[mx][left]*dp[mx-1][right]) 
//然后我们对dp前缀和,因为dp[mx][now]=∑i=1~mx tp[i][now]。不用关心i=0,因为对于非初始区间那里一定是0(A[i]>=1)(更实质地,只有虚区间会用到那个) 
il void dfs(int l,int r){re int now=id[l][r]; if(vis[now]) return; vis[now]=1;if(l>r){For(i,0,N) dp[i][now]=1; return;}if(l==r){if(A[l]<=L && R<=B[l])For(i,1,N) dp[i][now]=1;}if(l<r){For(mid,l,r)if(ok(l,mid,r)){dfs(l,mid-1); dfs(mid+1,r);if(A[mid]<=L && R<=B[mid])For(i,1,N) dp[i][now]=(dp[i][now] + dp[i][id[l][mid-1]] * dp[i-1][id[mid+1][r]]) % mod;}}For(i,1,N){dp[i][now]=dp[i-1][now]+dp[i][now];if(dp[i][now]>=mod) dp[i][now]-=mod;}return;
}ll son[maxn],sonqian[maxn],sonhou[maxn];
ll mu[maxn],invmu[maxn];
il void work(){for(re int i=1;i<totk;++i){L=key[i],R=key[i+1]-1,S=R-L+1;if(S<=usek){N=S;dfs(1,n);For(i,1,toti) dp[0][i]=dp[N][i];//每次都把上一段的结果放在0处,此时的1就代表L,相当于平移了整个dp数组 }else{N=usek;dfs(1,n);//首先我们处理分子 son 及其前后缀积。  拉插的代入值 x 应当为区间末端 R 。 sonqian[0]=sonhou[usek+1]=1; For(j,1,usek){//因为这里1代表L,所以rj(j为1~usek的任意值)=j+L-1son[j]=S-j;//实际的式子是son[j]=R-rj=R-L+1-j=S-j,由else知S>usek>=j,所以不用判负,而且 R<=1e9 ,所以也不用模 sonqian[j]=sonqian[j-1]*son[j]%mod;}foR(j,usek,1) sonhou[j]=sonhou[j+1]*son[j]%mod;//然后我们来处理分母For(i,1,usek){if(((usek-i)&1)==0) invmu[i]=invfact[i-1]*invfact[usek-i]%mod;else invmu[i]=mod-invfact[i-1]*invfact[usek-i]%mod;} for(re int i=1;i<=usek;++i){ll fenzi=sonqian[i-1]*sonhou[i+1]%mod;ll xishu=fenzi*invmu[i]%mod;For(now,1,toti)//暂时放在这里dp[N+1][now]=(dp[N+1][now]+xishu*dp[i][now])%mod;}For(now,1,toti) dp[0][now]=dp[N+1][now],dp[N+1][now]=0;}vis.reset();For(i,1,N)For(j,1,toti)dp[i][j]=0;//清空dp。}
}int main(){init();work();wt(dp[0][1]);return 0;
}

这篇关于P5469 [NOI2019] 机器人 洛谷黑题题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/641827

相关文章

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

C - Word Ladder题解

C - Word Ladder 题解 解题思路: 先输入两个字符串S 和t 然后在S和T中寻找有多少个字符不同的个数(也就是需要变换多少次) 开始替换时: tips: 字符串下标以0开始 我们定义两个变量a和b,用于记录当前遍历到的字符 首先是判断:如果这时a已经==b了,那么就跳过,不用管; 如果a大于b的话:那么我们就让s中的第i项替换成b,接着就直接输出S就行了。 这样

基于树梅派的视频监控机器人Verybot

最近这段时间做了一个基于树梅派 ( raspberry pi ) 的视频监控机器人平台 Verybot ,现在打算把这个机器人的一些图片、视频、设计思路进行公开,并且希望跟大家一起研究相关的各种问题,下面是两张机器人的照片:         图片1:                   图片2                    这个平台的基本组成是:

【秋招笔试】9.07米哈游秋招改编题-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收集 100+ 套笔试题,笔试真题 会在第一时间跟新 🍄 题面描述等均已改编,如果和你笔试题看到的题面描述

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

【机器人工具箱Robotics Toolbox开发笔记(二十)】机器人工具箱SerialLink I类函数参数说明

机器人工具箱中的SerialLink表示串联机器人型机器人的具体类。该类使用D-H参数描述,每个关节一组。SerialLink I类包含的参数如表1所示。 表1 SerialLink I类参数 参  数 意    义 参  数 意    义 plot 显示机器人的图形表示 jacobn 工具坐标系中的雅可比矩阵 plot3D 显示机器人3D图形模型 Jacob_dot

P2858 [USACO06FEB] Treats for the Cows G/S 题解

P2858 题意 给一个数组。每天把最左或者最右的东西卖掉,第 i i i个东西,第 d a y day day天卖出的价格是 a [ i ] ∗ d a y a[i]*day a[i]∗day。 记忆化搜索 void dfs(int l,int r,int day,ll sum){if(v[l][r]>=sum)return;v[l][r]=sum;if(l>r)//这就是dp答案{

高精度计算(代码加解析,洛谷p1601,p1303)除法待更新

目录 高精度加法 高精度减法 高精度乘法 高精度加法 我们知道在c++语言中任何数据类型都有一定的表示范围。当两个被加数很大时,正常加法不能得到精确解。在小学,我们做加法都采用竖式方法。那么我们也只需要按照加法进位的方式就能得到最终解。 8 5 6+ 2 5 5-------1 1 1 1 加法进位: c[i] = a[i] + b[i];if(c[i] >=