pat 甲级 1016 Phone Bills

本文讨论了一个关于电话费用计算的问题,通过使用前缀和优化算法,降低时间复杂度至O(n),满足了200ms的时间限制。描述了如何处理电话记录并计算在线和离线时段的费用差异。
摘要由CSDN通过智能技术生成

这道题是模拟题。需要处理的就是花费的话费,我们假设一个月有31天,那N<1000,每人最少两条数据,最多500个人,则复杂度为500*31*1440(每天的分钟)*24(24种话费情况),而时间限制是200ms,会超时。所以我们考虑用前缀和的思想,sum[]表示即当前的时间距离每月的0点0分所花费的话费,则电话的结束时间所花费的sum[]-电话的开始时间所花费的sum[],即为该时间段的话费。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
const int N=1010,M=31*1440+10;
int cost[24];
double sum[M];
struct record{//记录每条电话记录
    int minutes;//距离每个月的0时0分的分钟数,便于利用前缀和计算话费
    string state;//on-line还是off-line
    string formative_time;//格式化时间便于输出 00:00:00
    bool operator< (const record a){//重载运算符,使得结构体按时间从小到大排序
        return minutes<a.minutes;
    }
};
map<string,vector<record>> persons;//vector存储每个人的通话记录

int main(){
    for(int i=0;i<24;i++) cin>>cost[i];
    for(int i=1;i<M;i++) sum[i]=sum[i-1]+cost[(i-1)%1440/60]/100.0;//前缀数组初始化。i-1是因为6:59到7:00算的是6时的花费,所以要-1
    int n;
    cin>>n;
    char name[25],state[20],formative_time[20];
    int month,day,hour,minute;
    for(int i=0;i<n;i++){
        scanf("%s %d:%d:%d:%d %s",name,&month,&day,&hour,&minute,state);
        sprintf(formative_time,"%02d:%02d:%02d",day,hour,minute);//sprintf函数打印到字符串中
        int minutes=(day-1)*1440+hour*60+minute;
        persons[name].push_back({minutes,state,formative_time});
    }
    for(auto person:persons){
        auto name=person.first;//名字
        auto records=person.second;//记录数
        sort(records.begin(),records.end());//排序
        double total=0;
        for(int i=0;i+1<records.size();i++){
            auto a=records[i],b=records[i+1];
            if(a.state=="on-line"&&b.state=="off-line"){
                if(!total)
                    printf("%s %02d\n",name.c_str(),month);//输出名字跟月份
                cout<<a.formative_time<<" "<<b.formative_time;
                cout<<" "<<b.minutes-a.minutes<<" ";
                double c=sum[b.minutes]-sum[a.minutes];
                printf("$%.2lf\n",c);
                total+=c;
            }
        }
        if(total)
            printf("Total amount: $%.2lf\n", total);
    }
    return 0;
}

​

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值