P7426 [THUPC2017] 体育成绩统计 题解

累了就写个大模拟+博客,不得不说,意外的还挺减压

这题相比猪国杀简单不少,但是细节也挺多,还是考验实现能力。
说几个我觉得比较重要的实现的地方:
1 对于所有的时间,无论是分+秒,时+分+秒,日期,其实都可以转化成秒,因为2017年的秒数远小于int范围(大约也就7次方的水平),这样能够在特判的时候减少非常多的码量。同时最好每一条判断单独一个函数,可以直接return,一个else都不需要,也是降低了码量。
2 千米转化成米就没有浮点数问题了,同时除法尽可能写乘法,避开调精度。

除此之外就是一些坑:
1 注意所谓的时间相隔6小时是和上一次合法记录的,不合法的不算,同理,也不见得第一次取完之后就可以开始判断相隔这个条件了。
2 虽然并不存在,但是其实应该留意一下跑步跨过了一天的情况。
3 x个月的天数并不是28/30/31的倍数,更不是100天的倍数,记得预处理。
4 先计算阳光长跑计划,再加上专项计划算出勤。
5 跑步的时候是不低于该档算该档的分数(真的差一点就写错了)。
代码如下:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<unordered_map>
#include<cassert>
using namespace std;
const int N = 1e4 + 1;
const double eps = 1e-8;
struct run{
	long long date;
	double l;
	int st,ed,stp,step;
};
vector<run> v[N];
unordered_map<long long,int> mp;
int cnt[N],sum[N],mon[13] = {0,31,59,90,120,151,181,212,243,273,304,334,365};
long long id[N];
char tim[11],s[11],sex[N][2],heal[2],t[11];
bool flag[N];
int calctime1(){
	int x,y,z;
	x = (tim[1] - '0') * 10 + tim[2] - '0';
	y = (tim[4] - '0') * 10 + tim[5] - '0';
	z = (tim[7] - '0') * 10 + tim[8] - '0';
	return x * 3600 + y * 60 + z;
}//计算xx:yy:zz
int calctime2(){
	int i = 1,x = 0,y = 0,m;
	m = strlen(tim + 1);
	while(tim[i] >= '0' && tim[i] <= '9'){
		x = x * 10 + tim[i] - '0';
		++i;
	}
	++i;
	while(i <= m && tim[i] >= '0' && tim[i] <= '9'){
		y = y * 10 + tim[i] - '0';
		++i;
	}
	return x * 60 + y;
}//计算a'b''
int calctime3(){
	int x,y;
	x = (tim[5] - '0') * 10 + tim[6] - '0';
	y = (tim[7] - '0') * 10 + tim[8] - '0';
	return mon[x - 1] + y;
} //计算2017xxyy
int exam(int id){
	int x = calctime2();
	if(flag[id]){
		if(x <= 750) return 20;
		if(x <= 780) return 18;
		if(x <= 810) return 16;
		if(x <= 840) return 14;
		if(x <= 870) return 12;
		if(x <= 910) return 10;
		if(x <= 950) return 8;
		if(x <= 990) return 6;
		if(x <= 1030) return 4;
		if(x <= 1080) return 2;
		return 0;
	}
	else{
		if(x <= 400) return 20;
		if(x <= 417) return 18;
		if(x <= 434) return 16;
		if(x <= 451) return 14;
		if(x <= 470) return 12;
		if(x <= 485) return 10;
		if(x <= 500) return 8;
		if(x <= 515) return 6;
		if(x <= 530) return 4;
		if(x <= 540) return 2;
		return 0;
	}
}//测试成绩
int runsc(int x){
	if(x >= 21) return 10;
	if(x >= 19) return 9;
	if(x >= 17) return 8;
	if(x >= 14) return 7;
	if(x >= 11) return 6;
	if(x >= 7) return 4;
	if(x >= 3) return 2;
	return 0;
}//阳光长跑
int attend(int x){
	if(x >= 18) return 5;
	if(x >= 15) return 4;
	if(x >= 12) return 3;
	if(x >= 9) return 2;
	if(x >= 6) return 1;
	return 0;
}//出勤
int longrun(int id){
	#define u v[id][i]//减少码量
	int i,ret,ccnt = 0;
	long long lst,lstdate,ti,delta;
	bool valid,ok = 0;
	for(i = 0;i < (int)v[id].size();i++){
		valid = 1;
		assert(u.ed > u.st);
		if(u.ed < u.st){
			ti = u.ed + 86400 - u.st;
			--u.date;
		}
		else ti = (u.ed - u.st);
		if(u.stp > 270) valid = 0;
		if((int)u.l < 2 * ti || (int)u.l > 5 * ti) valid = 0;
		if(flag[id] && u.l < 3000 || !flag[id] && u.l < 1500) valid = 0;
		if(u.l > 1.5 * u.step) valid = 0;
		if(ok){
			delta = (u.date - lstdate) * 86400 + u.st - lst;
			if(delta < 21600) valid = 0;
		}
		if(valid){
			ok = 1;
			lstdate = u.date,lst = u.ed;
			++ccnt;
			//只有出现合法解之后再考虑相隔不超6小时的条件
		}
	}
	ret = runsc(ccnt);
	cnt[id] += ccnt;
	ret += attend(cnt[id]);
	return ret;
}
string grade(int sc){
	if(sc >= 95) return "A";
	if(sc >= 90) return "A-";
	if(sc >= 85) return "B+";
	if(sc >= 80) return "B";
	if(sc >= 77) return "B-";
	if(sc >= 73) return "C+";
	if(sc >= 70) return "C";
	if(sc >= 67) return "C-";
	if(sc >= 63) return "D+";
	if(sc >= 60) return "D";
	return "F";
}//利用string便于继续用前面的方法返回分数
int main(){
	int i,n,tt,temp;
	long long lemp;
	scanf("%d",&tt);
	for(i = 1;i <= tt;i++){
		scanf("%lld",&id[i]);
		mp[id[i]] = i;
		scanf("%s",sex[i] + 1);
		if(sex[i][1] == 'M') flag[i] = 1;
		scanf("%d",&sum[i]);
		scanf("%s",tim + 1);
		sum[i] += exam(i);
		scanf("%s",heal + 1);
		if(heal[1] == 'P') sum[i] += 10;
		scanf("%d",&temp);
		sum[i] += temp;
		scanf("%d",&cnt[i]);
	}
	scanf("%d",&n);
	run s;
	for(i = 1;i <= n;i++){
		scanf("%s",tim + 1);
		s.date = calctime3();
		scanf("%lld",&lemp);
		temp = mp[lemp];
		scanf("%s",tim + 1);
		s.st = calctime1();
		scanf("%s",tim + 1);
		s.ed = calctime1();
		scanf("%lf",&s.l);
		s.l *= 1000;
		scanf("%s",tim + 1);
		s.stp = calctime2();
		scanf("%d",&s.step);
		v[temp].push_back(s);
	}
	for(i = 1;i <= tt;i++){
		sum[i] += longrun(i);
		printf("%lld ",id[i]);
		printf("%d ",sum[i]);
		cout << grade(sum[i]) << endl;
	}
	return 0;
}

Thank you for reading 😃

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值