zoukankan      html  css  js  c++  java
  • 樱花庄的宠物女孩AtCoder Grand Contest 015E

    【问题背景】
    神田空大养了一群猫,因此被驱逐出了普通宿舍,搬进了樱花庄……
    【问题描述】
    神田空大养了 n 只猫,这 n 只猫开始时站在一条数轴上,第 i 只猫的位置是
    xi,保证 xi 互不相同。
    从0 时刻开始,所有猫同时向右走,第 i 只猫的速度为 vi,且自始至终保
    持这个速度。很明显,猫之间很可能会发生追及相遇。这里假设一只猫追上了另
    一只猫,即某一时刻两只猫在同一个位置,这两只猫将无视碰撞继续保持自己的
    速度走下去。
    还有一点很明显:经过了无穷的时间后,所有猫都不会再发生碰撞。
    现在猫中流行一种感冒,如果一只患了感冒的猫与另一只猫在某一时刻处于
    同一位置,那么后者将患上感冒。
    每只猫在 0 时刻都有可能患感冒或不患感冒。 神田空大想知道0 时刻 n
    2 种情
    况中有多少种情况能使所有猫都患上感冒。
    【输入格式】
    从文件 xtdoor.in 中读入数据。
    第一行一个整数 n 表示一共有 n 只猫。
    接下来 n 行每行两个整数 xi,vi,表示第 i 只猫在 0 时刻处于位置 xi,且
    速度为vi。
    【输出格式】
    输出到文件 xtdoor.out 中。
    一行一个整数,表示0 时刻有多少种情况能使所有猫都患上感冒。

    【样例输入】
    3
    2 5
    6 1
    3 7

    【样例输出】
    6

    【子任务】
    子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以
    尝试只解决一部分测试数据。
    每个测试点的数据规模及特点如下:
    对于 30% 的数据:n≤15
    对于 100% 的数据:n≤200000,0 < xi,vi≤1000000000

    分析:
    这道题可以说是有点难bu以ke理li解yu

    首先需要明确,在经过无穷大的时间后
    猫猫的排名会由速度决定

    一开始我们先按照x排序
    针对每一只猫猫,
    有两种猫会被ta感染
    位于此前但是速度小或者位于此后但是速度大
    这相当于一个速度区间

    确定每一只猫的感染范围的方法就是
    在按x排序后,
    找到第i只猫之前的最大速度Ri
    和第i只猫之后的最小速度Li,
    速度在[Li,Ri]的猫都可以被i感染
    (不要试图举出什么反例,这个区间内的猫可能不是被i直接传染,但最终结果都是患病)

    现在的问题就变成了已知一些连续的区间,
    覆盖[Vmin,Vmax]的所有方案数

    显然是dp

    因为每只猫的感染区间一定是单调不减的
    (感性的理解一下。。。)
    那我们把v离散化之后处理出每只猫的感染区间
    顺序枚举
    f[R[i]]=sigma(f[L[i]]+f[L[i]+1]+…+f[R[i]-1])
    //i是猫的编号
    写的优美一点
    这里写图片描述

    tip

    真正dp的时候,
    我们循环猫的编号
    所以这就导致f的意义有了一点变化:f[i]使用前i只猫覆盖整个区间的方案数
    sum表示区间和,
    用队列记录sum中包含哪些f[i]
    每次在进行下一次转移的时候,都暴力的进行sum的修改
    说白了就是只要是R小于当前L-1的f值都要减掉
    (这一部分是转移不到当前状态的)
    最后
    f[i]=sum
    sum+=f[i]
    f[i]入队

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    const int mod=1000000007;
    const int N=200005;
    int g[N],f[N],L[N],R[N],n,tot=0,q[N];
    struct node{
        int x,v,vv;
    };
    node po[N];
    
    int cmp1(const node &a,const node &b){return a.v<b.v;}
    int cmp2(const node &a,const node &b){return a.x<b.x;}
    
    void cl()
    {
        int i,j;
        int mx=0,mn=tot+1;
        for (i=1;i<=n;i++)  //单调不减 
        {
            mx=(po[i].vv>mx) ? po[i].vv:mx;
            R[i]=mx;
        }
        for (i=n;i>=1;i--)
        {
            mn=(po[i].vv<mn) ? po[i].vv:mn;
            L[i]=mn;
        }
        //for (i=1;i<=n;i++) printf("%d %d
    ",L[i],R[i]);
    }
    
    void dp()
    {
        int sum=0,tou=0,wei=0;
        L[0]=1;R[0]=0;
        f[0]=1;
        q[wei++]=0,sum=1;
        ++n;
        L[n]=R[n]=n;
        for (int i=1;i<=n;i++)  //循环猫的标号 
        {
            while (tou<wei&&L[i]>R[q[tou]]+1)  //用队列 
                sum=sum-f[q[tou]],sum%=mod,++tou;  //区间和 
            f[i]=sum;
            sum=sum+f[i];
            sum%=mod;
            q[wei++]=i;  //加入队列 
        }
        printf("%d",f[n]);
    }
    
    int main()
    {
        freopen("xtdoor.in","r",stdin);  
        freopen("xtdoor.out","w",stdout);   
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            scanf("%d%d",&po[i].x,&po[i].v);
        sort(po+1,po+1+n,cmp1);
        for (int i=1;i<=n;i++)
            if (po[i].v==po[i-1].v) po[i].vv=po[i-1].vv;
            else po[i].vv=++tot;
        sort(po+1,po+1+n,cmp2);
        cl();
        dp();
        return 0;
    }
  • 相关阅读:
    .net core Ocelot Consul 实现API网关 服务注册 服务发现 负载均衡
    .net core grpc 实现通信(一)
    Shell脚本
    LNMP学习内容总结①
    2018/12/18学习内容摘要
    2019/12/16学习内容摘要(Vim)
    第一周进度及学习总结
    2019/12/12学习内容摘要(Linux系统用户与用户组管理②)
    2019/12/13学习内容摘要(Linux磁盘管理①)
    2019/12/11学习内容摘要(Linux系统用户与用户组管理①)
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673414.html
Copyright © 2011-2022 走看看