兔崽小孩


 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述 

叉同学虽然是wf爷,但平时傻愣愣的,游戏也玩不过九峰,经常被九峰取笑。
 

有一次叉同学熬夜看球并在凌晨四点半和五点半连发两条说说,被早起水群的刘教主看到了,骂他道:"兔崽子,你这是玩通宵啊,不要命啦"。从此叉同学凌晨发说说总是慎之又慎,避免被骂。


假设叉同学入睡需要k分钟,且他必须醒着才能发说说,刘教主早上醒来后发现他肯定没睡够p分钟就会骂他,叉同学想知道自己是否会被骂。

输入描述:

第一行一个正整数n,q,n,q,表示说说条数和询问个数

第二行nn个正整数t_1,t_2,...,t_n,t1​,t2​,...,tn​,表示nn条说说的时间,保证t_i<t_{i+1}(i < n)ti​<ti+1​(i<n)

接下来qq行每行一次询问,每行两个正整数k,p,k,p,表示叉同学的入睡需要时间和刘教主认为叉同学需要的睡眠时间

输出描述:

对于每次询问,如果叉同学不会被骂则输出一行"Yes",否则输出一行"No"(不包括双引号)

示例1

输入

复制

5 2
1 2 5 9 10
3 1
3 2

输出

复制

Yes
No

说明

叉同学入睡需要3分钟,所以只可能在第3第4两条说说之间的4分钟间隔睡1分钟  

备注:

 n,q≤106

ti​≤109

k,p≤109
叉同学发第一条说说之前和发完最后一条说说之后视为一直醒着

答案错误做法:

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;
const int mas=1e6+5;
 int n,q,v[mas];
int res=-1;

int main()
{
      scanf("%d%d",&n,&q);
     scanf("%d",&v[1]);
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&v[i]);
        if(v[i]-v[i-1]>res)
            res=v[i]-v[i-1];
    }
    for(int i=1;i<=q;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a+b<=res)
            puts("Yes");
        else puts("No");
    }
    
    return 0;
}

误区:

当时想的是,选择时间最长的时间段,如果时间按段,时间足够入眠以及相对性的睡眠时间,则输出“Yes",否则“No”

实际上,每段是间可以分开,就是如果时间段超过入睡时间,则记录睡觉的时间长,将他累计睡眠的时间加和,超过规定的就输出“Yes”,否则就是“No”

区别就是在于时间和。

 运行超时的做法:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

int n,q,k,p;
vector<int>v;
vector<long long>sum;
long long x,res;

int main()
{
    scanf("%d%d",&n,&q);
    v.push_back(0);
    scanf("%lld",&x);
    for(int i=1;i<n;i++)
    {
        int temp;
        scanf("%d",&temp);
        v.push_back(temp-x);
        x=temp;
    }
    sort(v.begin(),v.end());
    while(q--)
    {
        res=0;
        scanf("%d%d",&k,&p);
        int l=1,r=v.size();
       while(l<r)//找到第一个大于等于k
        {
            int mid=l+r>>1;
            if(v[mid]<k)
                l=mid+1;
            else r=mid;//第一个模板
        }//一般的r 是结果
         for(int i=v.size()-1;i>=r;i--)
                 res+=(v[i]-k);
     
        if(res>=p)puts("Yes");
        else puts("No");
    }
    return 0;
}

问题出现:

时间复杂度的估计:

首先用sort函数,时间的复杂度为N(nlogn);

while循环N(n),二分寻找最左边的的刚好可以超过入睡时间的点N(logn),找到点后从左边的点向右遍历,时间复杂度位置,按照对坏的情况估计O(n)。第二步的时间复杂度为N(n*(n+logn)) .大概是N(n^2)级别

总体以上的时间复杂度为N(n^2)

因为n大概是10^6,绝对超时。

分析问题:时间的复杂度,sort的N(nlogn)不可避免。

                 while循遍N(n)和二分的N(logn)都不可避免。

                 实际可以进行优化的位置只有找到坐标后的遍历N(n),怎样优化呢,只需要进行一个                     级别的降低,就可以进行运行。很容易想到前缀和的思想。时间复杂度从N(n)降低至N                  (1)。

正确答案:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

int n,q,k,p;
vector<int>v;
vector<long long>sum;
long long x,res;

int main()
{
    scanf("%d%d",&n,&q);//从一开始
    v.push_back(0);
    scanf("%lld",&x);
    for(int i=1;i<n;i++)//用到前缀和从1开始
    {
        int temp;
        scanf("%d",&temp);
        v.push_back(temp-x);
        x=temp;
    }
  
    sort(v.begin(),v.end());
 
    sum.push_back(0);
    for(int i=1;i<n;i++)
    sum.push_back(sum[i-1]+v[i]);
    while(q--)
    {
        res=0;
        scanf("%d%d",&k,&p);
        int l=1,r=v.size();
       while(l<r)//找到第一个大于等于k
        {
            int mid=l+r>>1;
            if(v[mid]<k)
                l=mid+1;
            else r=mid;//第一个模板
        }//一般的r 是结果
        res=sum[sum.size()-1]-sum[r-1]-k*(sum.size()-r);
        if(res>=p)puts("Yes");
        else puts("No");
    }
    return 0;
}

但是对于push_back(),没有添加直接引用,出现好多问题呢 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值