P1167 刷题 模拟 排序 贪心

48 篇文章 0 订阅
3 篇文章 0 订阅

write题解之前吐槽一句:

这个题倒是不难但是敲代码敲得我手疼

 题目描述

NOIP 临近了,小 A 却发现他已经不会写题了。好在现在离竞赛还有一段时间,小 A 决定从现在开始夜以继日地刷题。也就是说小 A 废寝忘食,一天二十四小时地刷题。

今天的日期(时间)是 yyyy 年 mm 月 dd 日 hh 时 min 分,考试的时间是 yyyy2 年 mm2 月 dd2 日 hh2 时 min2 分。这之间的所有时间小 A 都用来刷题了,那么考试之前他最多能刷多少题呢?注意哦,考虑闰年。

时间紧张小 A 只管数量不管质量。当然有的题目容易一些,有的题目难一些。根据小 A 的经验,他能一眼看出写出某一个题目需要的时间,以分钟记。

现在给出洛谷 Online Judge 的题目列表,请你挑出最多的题目使小A能在竞赛前写出来。

我们假设从远古到未来,历法的表示与现在一样。

输入格式

第一行一个整数NN,表示洛谷Online Judge的题目数,N≤5000N≤5000。

接下来NN行,每行一个整数表示刷该题需要用的时间,以分钟记(\le 10000≤10000)。(这个题本身是什么并不重要,不是么?小A已经写过题目数为 00 个)。

接下来两行依次是当前时间和竞赛时间。时间给出的格式是:yyyy-mm-dd-hh:min,例如:2007-06-23-02:00,采用2424 小时制,每天从 00:00 到 23:59 ,年份从 00000000 到 99999999。

 

输出格式

一行,一个整数,NOIP 前最多刷的题目数。 

这题告诉我们重在平时,不要积累到最后变成小A这样

言归正传

讲思路:

其实就是计算一下从开始时间一直到结束时间之间的这个时间都能刷几道题

贪心策略:把每道题的时间从小到大排序,然后枚举(很简单就能想到吧QwQ)

重难点来了:怎么计算间隔时间?输入怎么搞?

 先说输入吧

这里顺便向大家介绍一种输入方式,也是我之前所有文章一直在用的

就是scanf和printf

这两个放到这题里作用可大了

这两个叫格式化输入输出,不懂的可以先自学一下,这题用cin比较费力

留下的可都是懂得的哈

接着往下走,有了这两个工具,输入直接简简单单轻轻松松

scanf("%lld-%lld-%lld-%lld:%lld",&year1,&month1,&day1,&hour1,&minute1);
scanf("%lld-%lld-%lld-%lld:%lld",&year2,&month2,&day2,&hour2,&minute2);

第二大难点:计算间隔时间

我们定义一个变量来表示间隔时间,这里就用sum

题里要求输出分,我们这里先把他单位设成天,这样比较容易做

首先考虑年:

因为有闰平年之分,所以我们浅浅写个函数做判断:

bool check(int x){
    if((x%4==0 && x%400!=0)||x%400==0){
    	return 1;
	}
    return 0;
}

那么我们逐年考虑,我们暂时先包括初始年,不包括结束年(如果你不懂为什么,很正常,带着你的问题往下看)

考虑年的代码:

    for (int i=year1;i<year2;i++){
		if (check(i)){
			sum+=366;
		}else{
			sum+=365;
		}
	}

这个无需多说了吧

其次考虑月

因为我们包括了初始年的所有天,但是有可能初始月不是在一月一号

?什么意思

画个小图

假设我们初始月份为五月

 

因为初始年考虑进去了,所以初始年的所有月都考虑进去了

可是一月二月三月四月并不是间隔时间,因为他们在初始月份之前

所以我们要把他减去

同理

结束年都没考虑,就得把结束月份之前的都考虑进去

这一部分的代码就出来了、

int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int b[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
if (check(year1)){
		for (int i=1;i<month1;i++){
			sum-=b[i];
		}
	}else{
		for (int i=1;i<month1;i++){
			sum-=a[i];
		}
	}
	if (check(year2)){
		for (int i=1;i<month2;i++){
			sum+=b[i];
		}
	}else{
		for (int i=1;i<month2;i++){
			sum+=a[i];
		}
	}

 然后考虑小时

因为我们已经到了小时了,sum的单位不够用了

所以先将sum*24,将单位变为小时

sum*=24;

然后和考虑月份的时候一样,减去多考虑的加上少考虑的

最后考虑分

继续变单位,然后减去多考虑的加上少考虑的

重难点说完了,接下来就是枚举了,直接上AC代码

# include <iostream>
# include <cstdio>
# include <algorithm>
using namespace std;
# define int long long
# define N 5005
int n;
int t[N];
int year1,month1,day1,hour1,minute1;
int year2,month2,day2,hour2,minute2;
int sum;
int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int b[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
bool cmp(int x,int y){
	return x<y;
}
bool check(int x){
    if((x%4==0 && x%400!=0)||x%400==0){
    	return 1;
	}
    return 0;
}
signed main(){
	scanf("%lld",&n);
	for (int i=1;i<=n;i++){
		scanf("%lld",&t[i]);
	}
	sort(t+1,t+1+n,cmp);
	scanf("%lld-%lld-%lld-%lld:%lld",&year1,&month1,&day1,&hour1,&minute1);
	scanf("%lld-%lld-%lld-%lld:%lld",&year2,&month2,&day2,&hour2,&minute2);
	for (int i=year1;i<year2;i++){
		if (check(i)){
			sum+=366;
		}else{
			sum+=365;
		}
	}
	//刨去多加的部分
	if (check(year1)){
		for (int i=1;i<month1;i++){
			sum-=b[i];
		}
	}else{
		for (int i=1;i<month1;i++){
			sum-=a[i];
		}
	}
	if (check(year2)){
		for (int i=1;i<month2;i++){
			sum+=b[i];
		}
	}else{
		for (int i=1;i<month2;i++){
			sum+=a[i];
		}
	}
	for (int i=1;i<day1;i++){
		sum--;
	}
	for (int i=1;i<day2;i++){
		sum++;
	}
	sum*=24;
	sum=sum-hour1+hour2;
	sum*=60;
	sum=sum-minute1+minute2;
	int cnt=0;
	for (int i=1;i<=n;i++){
		if (sum>=t[i]){
			sum-=t[i];
			cnt++;
		}else{
			break;
		}
	}
	printf("%lld",cnt);
	return 0;
}

AC记录:

 

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值