zoukankan      html  css  js  c++  java
  • b_pat_排序题目大杂烩(map+排序+模拟)

    最佳排名

    对于每个学生,输出他的最佳排名以及该排名对应的是哪项成绩。
    当多项排名相同,且都为最佳时,按照 A>C>M>E 的优先级,选择输出哪项成绩。
    如果无法查询到该学生的成绩,则输出 N/A。

    每门课也有很多下属(每个学生该门课的成绩);每个学生也有很多下属(每个学生的所有成绩);故需要两个结构

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2005;
    unordered_map<string, vector<int>> mp;
    vector<int> scores[4];
    
    int get_rk(int courseID, int score) {
        int l=0, r=scores[courseID].size();
        while (l<r) {
            int m=l+(r-l)/2;
            if (scores[courseID][m]>score) l=m+1;
            else r=m;
        }
        return l+1;
    }
    int main() {
        int n,m,info[4]; scanf("%d %d", &n, &m);
        string id;
        for (int i=0; i<n; i++) {
            cin>>id, memset(info, 0, sizeof info);
            for (int j=1; j<4; j++) scanf("%d", &info[j]), info[0]+=info[j];
            info[0]=round(info[0]/3.0);
            for (int j=0; j<4; j++) {
                mp[id].push_back(info[j]);   //id同学的成绩
                scores[j].push_back(info[j]);//第j门课的所有乘积
            }
        }
        for (int i=0; i<4; i++) sort(scores[i].begin(), scores[i].end(), [&](int a, int b){return a>b;});
    
        string sID;
        char course_name[4]={'A', 'C', 'M', 'E'};
        for (int i=0; i<m; i++) {
            cin>>sID;
            if (mp.find(sID)==mp.end()) printf("N/A\n");
            else {
                //得到sID的排名
                int rk=n+1;
                char course;
                for (int j=0; j<4; j++) {
                    int ans_rk=get_rk(j, mp[sID][j]);
                    if (ans_rk<rk) {
                        rk=ans_rk;
                        course=course_name[j];
                    }
                }
                printf("%d %c\n", rk, course);
            }
        }
        return 0;
    }
    

    PAT 排名

    然后用以下格式输出最终成绩排名列表:
    registration_number final_rank location_number local_rank
    具有相同分数的人的排名也要相同,相同分数的人,考号较小的先输出。

    先更新局部排名,再将更新好的学生node放到all数组中,然后更新all中的学生排名,最后输出信息

    #include<bits/stdc++.h>
    using namespace std;
    const int N=105;
    struct node {
        string sID;
        int score, localID, final_rk, local_rk;
    };
    int n;
    vector<node> locations[N];
    vector<node> all;
    bool cmp(node& a, node& b) {
        if (a.score!=b.score) return a.score>b.score;
        return a.sID<b.sID;
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int tot=0; cin>>n;
    
        for (int i=0; i<n; i++) {
            int k, score; cin>>k;
            string sID; 
            tot+=k;
            for (int j=0; j<k; j++) {
                cin>>sID>>score;
                locations[i].push_back({sID, score, i});
            }
            sort(locations[i].begin(), locations[i].end(), cmp);
            //更新局部排名
            for (int j=0; j<k; j++) {
                if (j==0 || locations[i][j].score!=locations[i][j-1].score) {
                    locations[i][j].local_rk=j+1;
                } else {
                    locations[i][j].local_rk=locations[i][j-1].local_rk;
                }
                all.push_back(locations[i][j]);
            }
        }
        cout<<tot<<'\n';
        sort(all.begin(), all.end(), cmp);
        for (int i=0; i<all.size(); i++) {
            if (i==0 || all[i].score!=all[i-1].score) 
                all[i].final_rk=i+1;
            else 
                all[i].final_rk=all[i-1].final_rk;
            cout<<all[i].sID<<' '<<all[i].final_rk<<' '<<all[i].localID+1<<' '<<all[i].local_rk<<'\n';
        }
        return 0;
    }
    

    pat评测

    以下列格式输出排名列表:
    rank user_id total_score s[1] ... s[K]
    其中,rank 是根据 total_score 计算的,所以拥有相同 total_score 的用户的 rank 也相同。
    s[i] 是第 i 个问题获得的分数。

    这种题一定要理清头绪,不能急啊,

    #include<bits/stdc++.h>
    using namespace std;
    unordered_map<string, vector<int>> mp;
    const int unsubmit=-2;
    struct node {
        string uID;
        int tot_score, ac_cnt;
        vector<int> k_score;
        int rk;
    };
    bool cmp(node& a, node& b) {
        if (a.tot_score!=b.tot_score) return a.tot_score>b.tot_score;
        if (a.ac_cnt!=b.ac_cnt) return a.ac_cnt>b.ac_cnt;
        return a.uID<b.uID; 
    }
    int main() {
        int n,k,m; scanf("%d%d%d", &n,&k,&m);    //总用户数,问题数,提交总数
        int p[k]; for (int i=0; i<k; i++) scanf("%d", &p[i]);
        char buff[15];
        int pID, score;
        for (int i=0; i<m; i++) {
            scanf("%s%d%d", buff, &pID, &score); string uID(buff);
            pID-=1;
            if (mp.find(uID)==mp.end()) mp.insert({uID, vector<int>(5+1, unsubmit)});
            mp[uID][pID]=max(mp[uID][pID], score);
        }
        vector<node> v;
        for (auto& info : mp) {
            string uID=info.first;
            auto& scores=info.second;
            int ac_cnt=0, tot_score=0, is_never_submit=true;
            for (int i=0; i<scores.size(); i++) {
                int s=scores[i];
                if (s!=-1 && s!=unsubmit) tot_score+=s,  is_never_submit=false;
                if (s==p[i]) ac_cnt++;
            }
            if (!is_never_submit) v.push_back({uID, tot_score, ac_cnt, scores});
        }
        sort(v.begin(), v.end(), cmp);
        for (int i=0; i<v.size(); i++) {
            if (i==0 || v[i].tot_score!=v[i-1].tot_score) {
                v[i].rk=i+1;
            } else {
                v[i].rk=v[i-1].rk;
            }
        }
        for (auto& a : v) {
            printf("%d %s %d", a.rk, a.uID.c_str(), a.tot_score);
            for (int j=0; j<k; j++) {
                if (a.k_score[j]==unsubmit) printf(" -");
                else if (a.k_score[j]==-1) printf(" 0");
                else printf(" %d", a.k_score[j]); 
            }
            printf("\n");
        }
        return 0;
    }
    

    校园内的汽车

    现在,给定你所有的有用信息,你需要做的是:

    • 对于一些查询,计算出查询时刻校园内的汽车数量。
    • 在一天结束时,找到在校园内停放时间最长的汽车
    
    

    电话账单

    对于每个客户,首先以示例显示的格式在一行中打印客户名称和帐单月份。
    然后,对于每个通话时间段,在一行中分别打印开始和结束时间和日期(dd:hh:mm),持续时间(以分钟为单位)和通话费用。
    通话必须按时间顺序列出。

    由于月份是相同的,故以输入月份的1号为基准值,将通过将输入的日期-基准值转化为分钟方便计算;

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005, ON=1, OFF=0;
    int cost[25];
    
    struct node {
        string name;
        int month,day,hour,minute,state,use_time;
    } A[N];
    
    double convert(node& info) {
        double ans=cost[info.hour]*info.minute+cost[24]*info.day*60;
        for (int i=0; i<info.hour; i++) ans+=cost[i]*60;
        return ans/100.0;
    }
    
    int main() {
        for (int i=0; i<24; i++) scanf("%d", &cost[i]), cost[24]+=cost[i];
        int n; scanf("%d", &n);
    
        for (int i=0; i<n; i++) {
            cin>>A[i].name; 
            scanf("%d:%d:%d:%d", &A[i].month, &A[i].day, &A[i].hour, &A[i].minute);
            A[i].use_time=A[i].day*24*60+A[i].hour*60+A[i].minute;
            string state_string; cin>>state_string;
            A[i].state=(state_string=="on-line" ? ON : OFF);
        }
        sort(A, A+n, [&](node a, node b) {
            return (a.name!=b.name) ? a.name<b.name : a.use_time<b.use_time;
        });
        map<string, vector<node>> mp;
        for (int i=1; i<n; i++) if (A[i].name==A[i-1].name && A[i-1].state==ON && A[i].state==OFF) {
            mp[A[i].name].push_back(A[i-1]);
            mp[A[i].name].push_back(A[i]);
        }
    
        for (auto& C : mp) {    //主人
            auto& records=C.second;
            double tot=0;
            printf("%s %02d\n", C.first.c_str(), records[0].month);
            for (int i=1; i<records.size(); i+=2) {
                auto start=records[i-1]; 
                auto& end=records[i];
                double d=convert(end)-convert(start);
                printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2f\n", start.day, start.hour, start.minute, end.day, end.hour, end.minute, end.use_time-start.use_time, d);
                tot+=d;
            }
            printf("Total amount: $%.2f\n", tot);
        }
        return 0;
    }
    

    研究生入学

    每个申请人都必须提供两个成绩:全国入学考试成绩 GE 和面试成绩 GI,申请人的最终成绩是 (GE+GI)/2。
    录取规则如下:

    • 申请者将根据其最终成绩由高到低进行排名,并且将从排名列表的顶部开始逐一录取。
    • 如果申请者的最终成绩并列,则按照 GE 成绩由高到低进行排名,如果成绩仍然并列,则并列者的排名必须相同。
    • 每个申请人可以填报 K 个志愿,并且将根据他/她的志愿进行录取:如果按照排名列表,轮到某位学生被录取了,并且其第一志愿学校还未招满人,则他成功被该学校录取。如果名额已满,则按顺序考虑其他志愿,直至成功被录取为止。如果所有报名学校都无法录取该名学生,则该名学生录取失败。
    • 如果出现并列排名,并且并列申请人正在申请同一所学校,那么该学校不得只录取其中一部分申请人,即使超过招生限额,也必须全部录取。

    每所学校的录取结果占据一行,其中包含所有学校录取的申请人的编号。编号必须按升序排列,并用空格分隔。
    每行的末尾必须没有多余的空格。如果某学校没有录取任何学生,则必须相应地输出空白行。

    耐心...

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4e5+5;
    struct node {
        int sID, Ge, Gi, Gf;
        int choise[6];
    } S[N];
    bool cmp1(node& a, node& b) {
        if (a.Gf!=b.Gf) return a.Gf>b.Gf;
        if (a.Ge!=b.Ge) return a.Ge>b.Ge;
        return a.sID<b.sID;
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n,m,k; cin>>n>>m>>k; //n是应用的总数,m是毕业院校总数,k学生的申请总数
        int limit[m];
        //第i个院校的限额
        for (int i=0; i<m; i++) cin>>limit[i];
        for (int i=0; i<n; i++) {
            cin>>S[i].Ge>>S[i].Gi;
            S[i].sID=i, S[i].Gf=S[i].Ge+S[i].Gi;
            for (int j=0; j<k; j++) {
                cin>>S[i].choise[j];
            }
        }
        sort(S, S+n, cmp1);
        //输出每个院校录取的学生编号
        vector<node> school[m];
        for (int i=0; i<n; i++) 
        for (int j=0; j<k; j++) {
            int schID=S[i].choise[j];
            if (limit[schID]>school[schID].size() || (school[schID].back().Ge==S[i].Ge && school[schID].back().Gf==S[i].Gf)) {
                school[schID].push_back(S[i]);
                break;  //如果考前的志愿被录取,则不考虑后面的志愿
            }
        }
        for (int i=0; i<m; i++) {
            sort(school[i].begin(), school[i].end(), [&](node a, node b) {return a.sID<b.sID;});
            for (int j=0; j<school[i].size(); j++) {
                auto& stu=school[i][j];
                if (j==school[i].size()-1) cout<<stu.sID;
                else cout << stu.sID << ' ';
            }
            cout<<'\n';
        }
        return 0;
    }
    

    校原内的汽车

    现在,给定你所有的有用信息,你需要做的是:

    • 对于一些查询,计算出查询时刻校园内的汽车数量。
    • 在一天结束时,找到在校园内停放时间最长的汽车。

    比较繁琐的一道:秒转化为时间 hh:mm:ss

    • hh=time/3600
      mm=time%3600/60比如1800对应1800/60=30(分针在30分钟的位置)
      ss=time%60
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e4+5, K=8e4+5;
    const char IN='i', OUT='o';
    struct node {
        string num;
        int time, isParking;
        char move;  //动作in/out
    } C[N];
    bool cmp(node& a, node& b) {
        if (a.num==b.num) return a.time<b.time; //优先考虑时间靠前的记录
        return a.num<b.num;
    }
    bool cmp1(node& a, node& b) {
        if (a.isParking==b.isParking) {
            if (a.time==b.time) return a.num<b.num;
            return a.time<b.time;
        }
        return a.isParking>b.isParking; //1>0,优先选出在
    }
    map<string, int> mp;
    int main() {
        int n,k; scanf("%d%d", &n,&k);
        char t[10], move[5];
        int hour,minute,second; 
        for (int i=0; i<n; i++) {
            scanf("%s %d:%d:%d %s", t,&hour,&minute,&second,move);
            C[i].num=string(t), C[i].time=hour*3600+minute*60+second, C[i].move=move[0];
        }
        sort(C,C+n,cmp);
        //记录每辆车的停车时间
        int max_parkingtime=0;
        for (int i=1; i<n; i++) if (C[i].num==C[i-1].num && C[i-1].move==IN && C[i].move==OUT) {
            mp[C[i].num]+=C[i].time-C[i-1].time;
            C[i].isParking=C[i-1].isParking=true;
            max_parkingtime=max(max_parkingtime, mp[C[i].num]);
        }
        //再排一下序,将不合法的车子弄到数组尾部
        sort(C, C+n, cmp1);
        int j=0, cnt=0;
        while (k--) {
            scanf("%d:%d:%d", &hour,&minute,&second);
            int deadline=hour*3600+minute*60+second;
            while (C[j].isParking && C[j].time<=deadline) {
                if (C[j].move==IN) cnt++;
                else               cnt--;
                j++;
            }
            printf("%d\n", cnt);
        }
        for (auto& info : mp) if (info.second==max_parkingtime) {
            printf("%s ", info.first.c_str());
        }
        printf("%02d:%02d:%02d", max_parkingtime/3600, max_parkingtime%3600/60, max_parkingtime%60);
        return 0;
    }
    

    快速排序的中轴

    给定一个序列,找到这个序列中可以作为快排中轴的元素

    思路
    傻了,一开始直接用单调栈求出右边大于自己的数的个数到 ans 数组中,然后中轴就是左边小于自己的数的个数为 n-ans[i]-1,这是不对的,比如:

    [1,3,2,4,5],2并不可以作为中轴,但 5-2-1=2,错误认为2是中轴
    

    冷静了一下,想了个暴力:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n; cin>>n;
        int A[n]; for (int i=0; i<n; i++) cin>>A[i];
    
        // stack<int> st;
        // int ans[n]; memset(ans, 0, sizeof ans);
        // for (int i=n-1; i>=0; i--) {
        //     while (!st.empty() && A[st.top()]<A[i]) st.pop();
        //     ans[i]=st.empty() ? 0 : n-st.top();
        //     st.push(i);
        // }
        // int cnt=0;
        // for (int i=0; i<n; i++) if (ans[i]==n-i-1) 
        //     cnt++;
        // cout << cnt << '\n';
        // for (int i=0; i<n; i++) if (ans[i]==n-i-1) { 
        //     if (i==n-1) cout << A[i];
        //     else cout << A[i] <<' ';
        // }
        int lmax[n], rmin[n]; 
        memset(lmax, 0, sizeof lmax), memset(rmin, 0x3f3f3f3f, sizeof rmin);
        lmax[0]=A[0], rmin[n-1]=A[n-1];
        for (int i=1; i<n; i++) lmax[i]=max(lmax[i-1], A[i]);
        for (int i=n-2; i>=0; i--) rmin[i]=min(rmin[i+1], A[i]);
        
        vector<int> ans; 
        for (int i=0; i<n; i++) if (A[i]>=lmax[i] && A[i]<=rmin[i]) {
            ans.push_back(A[i]);
        }
        sort(A.begin(), A.end());
        cout << ans.size() << '\n';
        if (ans.size()==0) cout << '\n';
        else for (int i=0; i<ans.size(); i++) {
            if (i==ans.size()-1) cout<<ans[i];
            else        cout<<ans[i]<<' '; 
        }
        return 0;
    }
    

    合影

    每行的人数必须为 N/K(向下取整),所有多余的人(如果有)都放到最后一行;
    位于后排的所有人都不得矮于位于前排的任何人;
    在每一行中,最高的人站在该行的中心位置(定义为位置 (m/2+1),位置从1开始编号,其中 m 是该行的总人数,除法结果向下取整);
    在每一行中,其他人必须按照其身高非递增顺序依次排入该行,交替地将他们的位置先安排到最高人的右侧,然后再安排到最高人的左侧
    身高相同时,必须按姓名的字典序升序进行排序

    思路
    这题如果真的是从中心开始扩张,每次扩张都需要用O(logn)时间(最优了吧)去找最高和次高进行安排,然后删除他两,比较慢;比较聪明的做法是:事先对学生数组 A 按照规则排序,对于每一行,从中心开始扩展,我都用一个数组记录扩张时的人的在 A 中的索引

    #include<bits/stdc++.h>
    using namespace std;
    struct node {
        string name;
        int h;
    };
    bool cmp(node& a, node& b) {
        if (a.h!=b.h) return a.h>b.h;
        return a.name<b.name;
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n,k; cin>>n>>k;
        node A[n+1];
        for (int i=0; i<n; i++) cin>>A[i].name>>A[i].h;
        sort(A, A+n, cmp);
        int idx=0;
        
        for (int i=0; i<k; i++) {
            int sz=round(n/k);
            if (i==0) sz+=n%k;
            int row[sz+1], m=sz/2+1, l=m-1, r=m;
            while (l>0 || r<=sz) {
                if (r<=sz) row[r++]=idx++;
                if (l>0) row[l--]=idx++;
            }
            for (int j=1; j<=sz; j++) {
                cout<<A[row[j]].name;
                if (j!=sz) cout<<' ';
            }
            cout<<'\n';
        }
        return 0;
    }
    

    世界首富

    接下来输出给定年龄段内最富有的 M 个人的信息,格式为:
    Name Age Net_Worth
    输出必须按照净资产的非递增顺序排列,如果净资产相同,则按照年龄不降序排列,如果年龄也相同,则按照字典序不降序排列。

    思路
    如果数据不卡暴力算法还好,就要优化:题目限定每个case最多输出100个人,所以可用一个数组记录每个年龄出现的次数,某个年龄出现次数多余100时,后面的人不用管了,反正都输出不了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    struct node {
        string name;
        int age, nw;
    };
    bool cmp(node& a, node& b) {
        if (a.nw!=b.nw) return a.nw>b.nw;
        if (a.age!=b.age) return a.age<b.age;
        return a.name<b.name;
    }
    int main() {
        int n,k; scanf("%d%d", &n, &k);
        node A[n];
        string name; 
        int age, nw;
        for (int i=0; i<n; i++) {
            cin>>A[i].name;
            scanf("%d%d", &A[i].age,&A[i].nw);
        }
        sort(A, A+n, cmp);
        int m, lo, hi;
        for (int i=0; i<k; i++) {
            scanf("%d%d%d", &m,&lo,&hi);
            printf("Case #%d:\n", i+1);
            vector<node> candidates;
            int cnt=0;
            while (cnt<m) {
                int i;
                for (i=0; i<n && cnt<m; i++) if (A[i].age>=lo && A[i].age<=hi) {
                    candidates.push_back(A[i]);
                    cnt++;
                }
                if (i==n) break;
            }
            sort(candidates.begin(), candidates.end(), cmp);
            if (candidates.empty()) printf("None\n");
            else for (auto& c : candidates) {
                printf("%s %d %d\n", c.name.c_str(), c.age, c.nw);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    VMware报错:无法连接 MKS: 套接字连接尝试次数太多;正在放弃
    java进阶学习计划
    js实现动态建立表格-------Day59
    Java通过POI技术操作Excel(3)----数据导出
    java通过POI技术操作Excel(2)----模板读取,录入数据
    Form表达元素美化篇----好看的搜索框(1)
    java通过POI技术操作Excel(1)----模板导出
    hibernate中 org.hibernate.MappingException: invalid configuration 报错
    中高级PHP程序员应该掌握哪些技术?
    Win10下Chrome浏览器无法安装 Adobe Flash Player 如何解决
  • 原文地址:https://www.cnblogs.com/wdt1/p/13687856.html
Copyright © 2011-2022 走看看