【倒计时10day 15/155】

【倒计时10day 15/155】

第一章字符串处理

1016 Phone Bills 电话账单

虽说是模拟题,我感觉非常难,非常麻烦…

重要思路

1.前缀和——计算时间时,以第一时刻的时间为借鉴点,每次都用时刻-开始时刻。他们之间的时间即为两个时间之差。
e.g.
t0=1月1日0时0分
t1=1月1日10时10分
t2=1月1日12时12分
t2-t1=(t2-t0)-(t1-t0)

程序化,减少了时间复杂度
2.初始化前缀和数组-难点

sum[i]=sum[i-1]+cost[(i-1)%1440/60]/100.0;
//(i-1)-计算的是前一个时刻所在的小时6:59-7:00算的是6点的钱
//%1440-有很多天,计算的是每天里面的24时刻
///60-看是哪个时刻的
///100.0-cost存的是美分,最后答案要美元,所以除100

char name[],state[];
scanf("%s %d:%d:%d:%d %s",name,&month,&day,&hour,&minute,state);
//注意,scanf char数组不用&

4.sprintf(format_time,"%02d:%02d:%02d",day,hour,minute);//格式化存储sprintf

Code

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
#define N 1010
#define M 31*1440+10//31day*24h*60
int n;
int cost[24];
double sum[M];//记录当月1号00:00开始到每个时刻所花费的时间

struct Record{
    int minutes;
    string statue;
    string format_time;
    bool operator<(const Record& t)const{
        if(minutes<t.minutes){
            return true;
        }
        return false;
    }
};
map<string,vector<Record>> persons;
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点的钱
        //%1440-有很多天,计算的是每天里面的24时刻
        ///60-看是哪个时刻的
        ///100.0-cost存的是美分,最后答案要美元,所以除100
    }
    cin>>n;
    char name[25],state[10],format_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);//注意,scanf char数组不用&
        int minutes=(day-1)*1440+hour*60+minute;//计算时刻
        sprintf(format_time,"%02d:%02d:%02d",day,hour,minute);//格式化存储sprintf
        persons[name].push_back({minutes,state,format_time});
    }
    for(auto &person:persons){
        auto record=person.second;
        sort(record.begin(),record.end());
        double total=0;
        for(int i=0;i<record.size()-1;i++){
            auto a=record[i],b=record[i+1];
            if(a.statue=="on-line"&&b.statue=="off-line"){
                if(!total){//这个人第一次输出
                    printf("%s %02d\n",person.first.c_str(),month);
                }
                printf("%s %s %d",a.format_time.c_str(),b.format_time.c_str(),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;
}

1017 Queueing at Bank银行排队问题

重要点

1.priority_queue优先队列
priority_queue<int,vector,greater> windows;
既然是队列那么先要包含头文件#include queue, 他和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队

优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的

和队列基本操作相同:

top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容

定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆

//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

2.逻辑
有空窗口,服务时间取决于来的时间,没有空窗口,服务时间取决于有空窗口的时间
start_time=max(p.arrive_time,w);
等待时间就是开始服务的时间-到达的时间
sum+=start_time-p.arrive_time;
再将开始时间+服务这个顾客的时间放入队列,成为这个窗口的有空的下一个时间,进入优先队列排序
windows.push(start_time+p.service_time);

Code

#include<iostream>
#include<algorithm>
#include<queue>
#define N 10010
#define M 110
using namespace std;
int n,m;
struct Person{
    //化简为以秒数为单位
    int arrive_time;
    int service_time;
    bool operator<(const Person& t)const{
        if(arrive_time<t.arrive_time){
            return true;
        }
        return false;
    }
}person[N];
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int hour,minute,second,servicetime;
        scanf("%d:%d:%d %d",&hour,&minute,&second,&servicetime);
        servicetime=min(servicetime,60);//服务时间不超过1h
        person[i]={hour*3600+minute*60+second,servicetime*60};
    }
    priority_queue<int,vector<int>,greater<int>> windows;
    sort(person,person+n);
    int sum=0;
    int cnt=0;
    for(int i=0;i<m;i++){
        windows.push(8*3600);//8点营业
    }
    for(int i=0;i<n;i++){
        auto p=person[i];
        auto w=windows.top();
        windows.pop();
        if(p.arrive_time>17*3600)break;
        int start_time=max(p.arrive_time,w);//有空窗口,服务时间取决于来的时间,没有空窗口,服务时间取决于有空窗口的时间
        sum+=start_time-p.arrive_time;
        cnt++;
        windows.push(start_time+p.service_time);
    }
    printf("%.1lf\n",(double)sum/cnt/60);
    return 0;
}

1060 Are They Equal 它们是否相等

重要点

1.逻辑清楚
(1)字符串找“.”,小数点的位置就是当前的10的次方的K值,如果没有找到K值那么说明是个整数,在串的最后面补全小数点,再找K值;
(2)字符串中去掉小数点
(3)如果字符串的大小为0,K=0
(4)如果字符串的大小不为0且字符串的第一个字符为“0”,不是有效数字,则去掉最开始的0,K–
(5)经过上面的步骤得到了有效数字串以及对应的K值,如果有效数字串的长度大于N(题目要求的有效数字数),substr去掉一部分;如果有效数字串的长度小于N,用“0”补齐

2.substr()
substr(pos,len)
substr(pos)=pos位置开始到结尾的字符串

3.string (len,char);新建len个长度的len个char字符
string(N-str.size(),‘0’)

Code

#include<iostream>
#include<string.h>
using namespace std;
string change(string a,int N){
    int k=a.find(".");
    if(k==-1){//没找到,补在最后,知道几位数
        a+='.';
        k=a.find(".");
    }
    string str=a.substr(0,k)+a.substr(k+1);//去掉小数点
    while(str.size()&&str[0]=='0'){//右移到有有效数字
        str=str.substr(1);
        k--;
    }
    if(str.empty()){
        k=0;
    }
    if(str.size()>N){//有效数字比N多
        str=str.substr(0,N);
    }else{//有效数字不够多-补0
        str+=string(N-str.size(),'0');
    }
    return "0."+str+"*10^"+to_string(k);
}
int main(){
    int N;scanf("%d",&N);
    string str1,str2;
    cin>>str1>>str2;
    str1=change(str1,N);
    str2=change(str2,N);  
    if(str1==str2){
        printf("YES %s\n",str1.c_str());
    }else{
        printf("NO %s %s\n",str1.c_str(),str2.c_str());
    }
    return 0;
}

第十四章基础算法与数据结构

1029 Median

注意

long int,scanf("%ld")
long long int,scanf("%lld")

Code

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
    int N;
    long int num;
    vector<long int> v;
    for(int i=0;i<2;i++){
        scanf("%d",&N);
        for(int i=0;i<N;i++){
            scanf("%ld",&num);
            v.push_back(num);
        }
    }
    sort(v.begin(),v.end());
    int mid=v.size()/2;
    if(v.size()%2==0){//偶数
        printf("%ld\n",v[mid-1]);
    }else{
        printf("%ld\n",v[mid]);
    }
    return 0;
}

1046 Shortest Distance

注意

1.思路上——前缀和把环拉直
S[0]=0
S[1]=dist<0,1>=dist[1]
S[2]=dist<0,2>=dist[i]+dist[2]
先存到一个预备数组里,就不用每次去循环(一开始我用的算法是每次都循环计算,所以运行超时了gg)

遇到只有一个样例输入,很多个样例输出时,多想想怎么用前缀和的办法解决

Code

#include<iostream>
#include<math.h>
using namespace std;
void getshortest(int start,int end,int S[],int N,int count){
    int dist1=abs(S[(end-1+N)%N]-S[(start-1)%N]);//1顺时针,2逆时针
    int dist2=count-dist1;
    int res=dist1<dist2?dist1:dist2;
    printf("%d\n",res);
}
int main(){
    int N,M,cnt=0;
    scanf("%d",&N);
    int S[N];
    S[0]=0;
    int dist[N];
    for(int i=0;i<N;i++){
        scanf("%d",&dist[i]);
        S[i+1]=cnt+dist[i];//前缀和
        cnt+=dist[i];
    }
    scanf("%d",&M);
    int start,end;
    for(int i=0;i<M;i++){
        scanf("%d %d",&start,&end);
        getshortest(start,end,S,N,cnt);
    }
    return 0;
}

1085 Perfect Sequence 完美数列

思路

排序后,找满足不等式的最长区间

Code

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    long long N,p,Max,t;
    int cnt=0;
    scanf("%ld %ld",&N,&p);
    long long A[N];
    for(int i=0;i<N;i++){
        scanf("%ld",&A[i]);
    }
    sort(A,A+N);
    for(int i=0,j=0;i<N;i++){
        while(A[j]*p<A[i])j++;//j是min i是max
        cnt=max(cnt,i-j+1);
    }
    printf("%ld\n",cnt);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值