时间限制: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(),没有添加直接引用,出现好多问题呢