测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A22562. 我要飞得更高(rocket)

填空题 较难

题目描述

我要飞得更高(rocket)

题目描述

你是一只毛毛虫,想要飞离地球前往空间站。空间站位于距离地球n千米的位置,在1∼n−1的每整数千米位置都有一个休息站。你最开始在地球上,距离地球0千米。为了飞到空间站,你准备了m种火箭,其中i 号火箭能够前进Li--Ri千米。为了顺利到达空间站,有如下的限制条件:

1、每种火箭可以重复使用,且没有使用顺序的限制。

2、每次前进后,如果无法到达空间站,你需要到达距离地球整数千米的位置的休息站,在休息站修整后重新使用某种火箭,直到到达空间站。

3、宇宙很大,一旦和地球的距离超出了n千米就会失联,迷失在宇宙中,因此要避免这种情况。出发前,你想算算顺利到达空间站有几种方案,因为方案数可能很多,你只需要输出方案数对998244353 取模的结果。前进次数不同或前进次数相同但是存在某一步前进距离不同,则认为两个方案不同。

输入格式

第一行两个空格隔开的正整数表示n和m。

接下来m行,第i+1行两个空格隔开的正整数Li,Ri 描述第i个火箭的能力。

输出格式

输出一行一个非负整数表示方案数对998244353取模的结果。

样例输入1:

3 2
1 3
2 2

样例输出1:

4

样例输入2:

5 1
3 4

样例输出2:

0

说明/提示

【样例1解释】

第一个火箭可以让你前进1、2或3千米,第二个火箭可以让你前进2千米。到达1千米位置的休息站的方案只有一个,就是从地球前进1千米。到达2千米位置的休息站的方案有两个,一个是前进2千米,一个是前进1千米再前进1千米。到达3 千米的空间站的方案有四个,分别是前进3、前进2再前进1、前进1前进2、前进1前进1再前进1。询问你到达3千米的空间站的方案数,所以输出4。

【样例2解释】

只有一种火箭,可以让你前进3或4千米。到达3千米和4千米位置的休息站的方案都是1。无论怎么前进都只能停在中间或者距离超出5千米,无法顺利到达空间站,因此到达空间站的方案为0。

【测试点约束】对于所有数据,1≤n≤10^5,1≤m≤200,1≤Li ≤Ri≤n。



参考答案

#include<bits/stdc++.h> using namespace std; int n, m, cnt; const int MOD=998244353; long long dp[100005]; long long pre[100005]; struct qwe{ //统计区间的结构体 int l,r; }a[205],A[205]; //a统计原区间,A统计合并后的区间 bool cmp(qwe x,qwe y){ //方便合并的排序规则 if(x.l!=y.l){ return x.l<y.l; }else{ return x.r<y.r; } } int main(){ cin>>n>>m; for(int i=1;i<=m;i++){ cin>>a[i].l>>a[i].r; } //设置一个无效的区间,用来标记结尾,方便最后一个区间放入A a[m+1]={100005,100005}; sort(a+1,a+m+1,cmp); //按左端点排序,方便我们区间的合并 int k=0; //统计合并后的区间数量 int L=a[1].l,R=a[1].r; //用L,R表示当前正在合并的区间范围 //注意这里要设置无效区间,保证最后一个正常区间的统计 for(int i=2;i<=m+1;i++){ if(a[i].l<=R){ //若第i个区间左端点落在L-R的范围内,则合并 R=max(a[i].r,R); //判断区间长度有没有拓展 }else{ //若不能合并,将合并好的区间(L,R)放入A中 A[++k].l=L; A[k].r=R; L=a[i].l; //开启新的区间合并 R=a[i].r; } } //注意:这里如果不设置a[m+1],不容易处理最后一个区间放入A的过程,容易导致错误 dp[0]=1; pre[0]=1; //前缀和数组 for(int i=1;i<=n;i++){ for(int j=1;j<=k;j++){ int left=i-A[j].r; int right=i-A[j].l; //(left~right)范围内都可到达i位置 if(right<0){ //若右端点小于0,表示范围不存在,跳过 continue; } if(left<0){ //左端点小于0则从0开始 left=0; } if(left-1>=0) //经典前缀和求区间累加的方法,不再赘述 dp[i]=(dp[i]+pre[right]-pre[left-1]+MOD)%MOD; else dp[i]=(dp[i]+pre[right])%MOD; //right>=left-1>=0,我们只需计算0~right累加之和pre[right] } pre[i]=(pre[i-1]+dp[i]%MOD)%MOD; //更新前缀和数组 //求余时选择+MOD再求余,一个避免负数求余出错的好习惯 } cout<<dp[n]; return 0; }
上一题 下一题