Codeforces Beta Round 79 (Div. 2 Only)-D 离散化+前缀和+二分+DP

题目传送门

题目

小男孩Gerald在离他家很远的学校上学。这就是为什么他每天都要坐公共汽车去那里。从家到学校的路用一段直线表示;该段恰好包含n+1个公交站点。所有的房子都用从0到n的整数编号,按照Gerald家的顺序排列。Gerald家附近的公共汽车站是0号,学校附近的公共汽车站是n号。

有m辆公共汽车在房子和学校之间运行:第i辆公共汽车从si站到ti站(si<ti),按照它们在这段路上的顺序访问所有中间站。再说,杰拉尔德也不傻,他不会在离学校不远的地方下车(显然,下车完全没有意义)。换句话说,Gerald可以在从si到t i-1(包括t i-1)的任何车站乘坐第i路公共汽车,但他只能在第i路公共汽车的第ti站下车。Gerald不能在公共汽车站之间步行,也不能从学校到房子的方向移动。杰拉尔德想知道他从家到学校要走多少条路。告诉他这个号码。如果Gerald在不同的巴士站之间穿过某一段,则两条路被认为是不同的。由于方法的数量可能太多,请找出这个数字除以1000000007(1e9+7)的余数。

输入:

第一行包含两个用空格分隔的整数:n和m (1 <n<10^9,0<m<10^5)。然后跟着m行,每行包含两个整数si和ti。它们是公交车的起始站点和结束站点的编号(0 <=si<ti<=n)。

输出:

打印唯一的数字-到学校的方法的数量取模1000000007(1e9+ 7)。

题目大意:

给出所有的公交路线和目的地,Gerald可以在一段公交路线的任意位置上车,但是上车必须到终点才能下车,计算所有的路线的数量并对1e9+7取模 。时间限制为2000ms 。

思路

如果直接遍历从0~终点n的所有可能,因为n范围为1e9会T掉,所以需要用到离散化的方法,同时因为必须在终点站下车,所以只需要取所有的终点就行。然后因为可以在si到t i-1容易处上车,所以到一个公交的终点站的路线是到si~t i-1的路线和,所以用到前缀和去存,每一个车站的路线数量为sum[ti-1]-sum[si -1],同时因为离散化时只取了终点,所以用二分函数lower_bound函数去查找第一个可以上车的车站位置代替ti,用dp数组来储存到达某站的方法数量

代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<list>
#define int long long
#define PII pair<int,int>
//priority_queue<PII,vector<PII>,greater<PII> >q;
using namespace std;
const int N=2e5+5;
const int mod=1e9+7;
struct stu{
    int s,t;
}a[N];
bool cmp(stu a,stu b)
{
    if(a.t==b.t)
        return a.s<b.s;
    return a.t<b.t;
}
int p[N],f[N],sum[N];
void solve()
{
    int n,m;
    cin>>n>>m;
    map<int,int>mp;
    int q=0;
    p[++q]=0;
    mp[0]=q;
    for(int i=1;i<=m;i++)
    {
        cin>>a[i].s>>a[i].t;
    }
    sort(a+1,a+1+m,cmp);
    for(int i=1;i<=m;i++)
        if(!mp[a[i].t])
        {
            p[++q]=a[i].t;
            mp[a[i].t]=q;
        }
    f[1]=1;sum[1]=1;
    for(int i=1;i<=m;i++)
    {
        int k=lower_bound(p+1,p+1+q,a[i].s)-(p+1);
        f[mp[a[i].t]]=(f[mp[a[i].t]]+sum[mp[a[i].t]-1]-sum[k]+mod)%mod;
        sum[mp[a[i].t]]=(sum[mp[a[i].t]-1]+f[mp[a[i].t]]+mod)%mod;    
    }
    cout<<f[mp[n]];    
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
//    int T;
//    cin>>T;
//    while(T--)
        solve();
    return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值