复建的第一题
理解题意
读懂题目就是一个活,所以我们用观察输出法,可以看出来月份,以及时间和费用之间的关系。
定义过程
然后时间要用什么来记录呢?day hour minute 好麻烦呀。。用字符串吧也可以比较大小的
看到这种结果分组的(就像是数据库里面group by之后的结果)就想到用map<string,xxx>
在这道题里面,xxx就是个容器里面存放了打电话挂电话的时间戳,
这个时间戳应该是用结构体的定义,首先需要是电话或者挂电话的时间点,还有这个时间点转化为的数字,以及状态。
题意延展
下一个难点就是计算费用,这里是参考别人的,利用打表的方式,把每分钟的费用给计算出来,这样再根据时间戳就可以减出整个对话长度的话费。
具体操作
剩下的就简单了,就是录入数据排下去,然后按每个人头(name)处理一下。<name,vector<record>> first second
这里遍历就是auto,vector<record>一层的遍历是要两个两个遍历(这里是这个题的特色,因为他要求人在同一个时间段不可能有两个通话,所以以排序为主,出现的两个相邻而且是一个on一个end的就是我们要的区间,合法的区间)
输出要求
根据输出,我们可以看到,当这个人开始第1次输出的时候,要输出他的名字以及月份,后面要跟上话费以及最后要输出总话费,所以我可以通过话费来判断是否是输出名字还是输出时间条目。
ac代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1000,M=24*60,minuteOfAMonth=31*M+10; 4 struct record{ 5 int minute; 6 string formatTime; 7 string state; 8 }; 9 bool cmp(record a,record b){ 10 return a.minute<b.minute; 11 } 12 map<string,vector<record>> records; 13 double sum[minuteOfAMonth]; 14 int money[25]; 15 int main(){ 16 int n; 17 for(int i=0;i<24;i++) cin>>money[i]; 18 for(int i=1;i<minuteOfAMonth;i++)sum[i]=sum[i-1]+money[(i-1)%M/60]/100.0; 19 cin>>n; 20 int month,day,hour,minute; 21 char name[25],state[10],formatTime[25]; 22 for(int i=0;i<n;i++){ 23 scanf("%s %d:%d:%d:%d %s",name,&month,&day,&hour,&minute,state); 24 int minutes=(day-1)*M+60*hour+minute; 25 sprintf(formatTime,"%02d:%02d:%02d",day,hour,minute); 26 records[name].push_back({minutes,formatTime,state}); 27 } 28 for(auto a:records){ 29 double total=0; 30 string name=a.first; 31 auto person=a.second; 32 sort(person.begin(),person.end(),cmp); 33 for(int i=0;i+1<person.size();i++){ 34 auto a=person[i],b=person[i+1]; 35 if(a.state=="on-line"&&b.state=="off-line"){ 36 if(!total){ 37 printf("%s %02d ",name.c_str(),month); 38 } 39 double charge=sum[b.minute]-sum[a.minute]; 40 printf("%s %s %d $%.2lf ",a.formatTime.c_str(),b.formatTime.c_str(),b.minute-a.minute,charge); 41 total+=charge; 42 } 43 } 44 if(total)printf("Total amount: $%.2lf ",total); 45 } 46 47 }
新知
ps:sprintf真的灵性,学到了。可以这样构建字符串。
sprintf(a,"%02d",name);//name以%02d的格式输入到a中。