大一寒假培训(二)——快排与桶排

大一寒假培训(二)

今天是寒假培训的第二天,今天学了快排和桶排。以下是今天做的习题。

nefu 1481 谁考了第k名-排序

Description
在一次考试中,每个学生的成绩都不相同,现知道了每个学生的学号和成绩,求考第k名学生的学号和成绩。
Input
第一行有两个整数,分别是学生的人数n(1≤n≤100),和求第k名学生的k(1≤k≤n)。
其后有n行数据,每行包括一个学号(整数)和一个成绩(浮点数),中间用一个空格分隔。
Output
输出第k名学生的学号和成绩,中间用空格分隔。(注:请用%g输出成绩)
Sample Input
5 3
90788001 67.8
90788002 90.3
90788003 61
90788004 68.4
90788005 73.9
Sample Output
90788004 68.4

#include <bits/stdc++.h>
using namespace std;
typedef struct stu{
    int num;
    double grade;
}stu;
stu p[200];
int cmp(stu a,stu b)	//按成绩从大到小的顺序排序
{return a.grade>b.grade;}
int main()
{
    int n,k;
    while(cin>>n>>k){
        for(int i=0;i<n;i++)
            cin>>p[i].num>>p[i].grade;
        sort(p,p+n,cmp);
        printf("%d %g\n",p[k-1].num,p[k-1].grade);
    }
    return 0;
}

nefu 1482 奇数单增序列

Description
给定一个长度为N(不大于500)的正整数序列,请将其中的所有奇数取出,并按升序输出
Input
共2行:
第1行为 N;
第2行为 N 个正整数,其间用空格间隔。
Output
增序输出的奇数序列,数据之间以逗号间隔。数据保证至少有一个奇数。
Sample Input
10
1 3 2 6 5 4 9 8 7 10
Sample Output
1,3,5,7,9

#include <bits/stdc++.h>
using namespace std;
int num1[500],num2[500];
int main()
{
    int n,j;
    while(cin>>n){
        j=0;
        for(int i=0;i<n;i++)	//输入数据
            cin>>num1[i];
        for(int i=0;i<n;i++)	//将奇数从num1数组中取出,放到num2数组
            if(num1[i]%2)
                num2[j++]=num1[i];
        sort(num2,num2+j);	//默认从小到大排序
        for(int i=0;i<j;i++){
            if(i==j-1)
                cout<<num2[i]<<endl;
            else
                cout<<num2[i]<<',';
        }
    }
    return 0;
}

nefu 1483 成绩排序

Description
给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。
Input
第一行为n (0 < n < 20),表示班里的学生数目;
接下来的n行,每行为每个学生的名字和他的成绩, 中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大于100的非负整数。
Output
把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。
Sample Input
4
Kitty 80
Hanmeimei 90
Joey 92
Tim 28
Sample Output
Joey 92
Hanmeimei 90
Kitty 80
Tim 28

#include <bits/stdc++.h>
using namespace std;
typedef struct stu{
    char name[20];
    int grade;
}stu;
stu p[20];
bool cmp(stu a,stu b)	//先按成绩排序,若成绩相同,则按名字字典顺序排序
{
    if(a.grade==b.grade) return strcmp(a.name,b.name)<0;
    else return a.grade>b.grade;
}
int main()
{
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++)
            cin>>p[i].name>>p[i].grade;
        sort(p,p+n,cmp);
        for(int i=0;i<n;i++)
            cout<<p[i].name<<' '<<p[i].grade<<endl;
    }
    return 0;
}

没什么好说的,基础的结构体快排。

nefu 1659 没必要的排序1

Description
羽裳有n个数,她想知道前k大的数的和为多少
Input
首先输入两个数n,k,代表有n个数,求前k大的和,接下来输入n个数,这n个数或是0或是1.
1<=k<=n<=1000
Output
输出一个数,为前k大的和
Sample Input
5 3
0 0 1 0 1
Sample Output
2

#include <bits/stdc++.h>
using namespace std;
int num[1000];
int main()
{
    int n,k,sum;
    while(cin>>n>>k){
        for(int i=0;i<n;i++)
            cin>>num[i];
        sort(num,num+n,greater<int>());		//按照从大到小排序
        sum=0;
        for(int i=0;i<k;i++)
            sum+=num[i];
        cout <<sum<<endl;
    }
    return 0;
}

nefu 1650 没必要的排序2

Description
羽裳有n个数,她想知道前k大的数的和是多少
Input
输入n,k代表有n个数,求前k大的和,之后输入n个数,第i个数为a[i]
1<=n<=10000000(1e7)
1<=k<1000
对任意的i
1<=a[i]<=100000(1e5)
Output
输出一个数ans,ans是前k大数的和
Sample Input
2 1
99999 1
Sample Output
99999

前一道题的加强版。
说实话做这道题的时候,想用快排直接做,结果直接TLE了。
后来想了想,考虑用桶排做,果然对了。

#include <bits/stdc++.h>
using namespace std;
int a[100001]={0};	//创建一个1e7的桶
int main()
{
    long long ans;
    int n,k,x,z;
    while(cin>>n>>k){
        for(int i=1;i<=100000;i++)
            a[i]=0;
        for(int i=0;i<n;i++){	//输入数据,并把它放进桶中
            cin>>x;
            a[x]++;
        }
        ans=z=0;
        for(int i=100000;i>0;i--){	//从大到小累加,发现加多之后,把多余部分去除
            if(a[i]){
                z+=a[i];
                ans+=a[i]*i;
                if(z>=k){
                    ans-=i*(z-k);
                    break;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

中间加和的时候还可以这样

if(a[i]){		//这个方法好在每次只加a[i]和k-z的最小值,不会出现多加的情况
    ans+=min(a[i],k-z)*i;
    z+=a[i];
    if(z>=k)	break;
}

nefu 554 老和尚的导员

Description
等小和尚回来后,老和尚居然没有睡觉。老和尚表示他的导员的excel表格坏掉了(老和尚居然有导员?好吧……据说是方丈),而且老和尚的导员要老和尚将寺中所有和尚的期末考试成绩按降序排列来发奖学金(和尚还有奖学金?)
不用多说,为了继续睡午觉,这个任务理所当然的落在了小和尚身上。所有……你继续帮忙吧。
Input
寺中主要考试科目有C语言,线性代数,高等数学和英语四个科目(怎么当和尚都这么累),输入的第一行是和尚的人数N(N<=100),第二行至第N+1行分别为C语言a[i],线性代数b[i],高等数学c[i]和英语的成绩d[i](0 <= a[i],b[i],c[i],d[i] <= 100)。
Output
现需要你将和尚们的成绩以总成绩降序排列,输出数据的每行有两个数字,第一个数字为和尚的编号(输入时的第一个和尚成绩即为和尚1,第二个为和尚2),第二个数字为和尚的总成绩(如果总成绩相同,则按C语言的成绩排列,如在相同,则按线性代数输出编号,以此类推。)
Sample Input
5
98 50 27 65
58 52 24 16
98 96 90 89
31 65 98 78
65 67 66 90
Sample Output
3 373
5 288
4 272
1 240
2 150

#include <bits/stdc++.h>
using namespace std;
typedef struct stu{
    int num,sum;
    int c;		//C语言成绩
    int xd;		//线代成绩
    int gs;		//高数成绩
    int yy;		//英语成绩
}stu;
stu a[100];
bool cmp(stu a,stu b)	//函数以return为结束,所以可以不必写else
{
    if(a.sum!=b.sum)    return a.sum>b.sum;		//先按总成绩排序
    if(a.c!=b.c)        return a.c>b.c;			//总成绩相同,按C语言成绩排序
    if(a.xd!=b.xd)      return a.xd>b.xd;		//C语言成绩相同,按线代成绩排序
    if(a.gs!=b.gs)      return a.gs>b.gs;		//线代成绩相同,按高数成绩排序
                        return a.yy>b.yy;		//高数成绩相同,按英语成绩排序
}
int main()
{
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            cin>>a[i].c>>a[i].xd>>a[i].gs>>a[i].yy;
            a[i].num=i+1;	//对每个和尚进行标号
            a[i].sum=a[i].c+a[i].xd+a[i].gs+a[i].yy;	//求总成绩
        }
        sort(a,a+n,cmp);	//调用cmp函数,按照cmp函数的要求排序
        for(int i=0;i<n;i++)
            cout << a[i].num << " " << a[i].sum <<endl;
    }
    return 0;
}

nefu 556 健忘的老和尚

Description
当小和尚排完名单后,老和尚突然一拍脑袋:“导员把每个人的人名都给我了,可我忘记告诉你了。”好吧……我们可怜的小和尚看来要费二遍事了(好像之前的任务都是你帮他做的,好吧,你真可怜)
Input
输入数据为多组,输入的第一行为和尚的人数N,可以得到奖学金的人数M,和需要补考的人数O(在这里可以满足M+O<=N,即得到奖学金的和尚一定不用参加补考)。之后的N行每行都有一个字符串(即为和尚的名字,长度小于100)和尚考试的总分a[i](0 <= a[i] <= 1000)。
Output
前M行,每行是获得奖学金的小和尚的名字;
后O行,每行是补考的小和尚的名字;
由于老和尚觉得很对不起小和尚,所以他决定这次简单些,所以无论是奖励还是惩罚都按照总成绩从低到高输出和尚的名字即可。
Sample Input
5 1 2
a 192
aa 212
ab 351
bab 128
bbaa 654
Sample Output
bbaa
bab
a

#include <bits/stdc++.h>
using namespace std;
typedef struct stu{
    char name[100];
    int grade;
} stu;
stu a[100];
bool cmp(stu a,stu b)		//按照成绩从低到高排序
{return a.grade<b.grade;}
int main()
{
    int n,m,o;s
    while(cin>>n>>m>>o){
        for(int i=0;i<n;i++)
            cin>>a[i].name>>a[i].grade;
        sort(a,a+n,cmp);
        for(int i=n-m;i<n;i++)		//题目要求先输出有奖学金的,再输出补考的
            cout<<a[i].name<<endl;
        for(int i=0;i<o;i++)
            cout<<a[i].name<<endl;
    }
    return 0;
}

nefu 873 戏说三国

Description
东汉末年,宦官当权,民不聊生。灵帝中平元年,张角兄弟发动黄巾起义,官军闻风丧胆。为抵抗黄巾,幽州太守刘焉出榜招兵。榜文前,刘备、关羽、张飞三兄弟萍水相逢。三人都有为国效力之心,于是桃园结为异姓兄弟,开始了一段三国浪漫传奇……
如果我问你三国中谁最聪明你一定会说是诸葛亮,我要问你谁武功最高,保不准你就要说关羽。是啊,我们的刘备对于优秀的手下向来十分满意。可是有一天,刘备在无意间在朋友圈里看到了梁山的宋江正在进行英雄排座次,最可气的是这条动态已经被转发评论了无数次了……这一下可气坏了刘备,他决定也来一次,蜀中文武百官大排名。
为了公平起见,诸葛亮帮他制定一条评分标准:每个官员有一个智育、德育、武育三个分数,分别以b%,a%,c%的比率计入加权总分,按总分降序排列,总分相同按智育折合后的分数降序,智育相同按德育,依次类推最终决定排名。(保证没有排名一样的两个人)
Input
输入第一行t(1<=t<=1000)表示输入的组数。接下来每组第一行1个整数n(1<=n<=100000)三个实数a,b,c(a+b+c=100)接下来n行每行包括英雄的名字,字符串s(1<=len<=20,全为小写字母) 智育、德育、武育的分数(整数)。(1~100)
Output
每组第一行输出是第几组输出Case #t:接下来输出n行每行包括英雄的名字,总分,智育、德育、武育折合后的分数(保留四位小数)。
Sample Input
1
3 20.00 20.00 60.00
zhugeliang 90 80 0
zhangfei 0 0 100
guanyu 10 100 100
Sample Output
Case #1:
guanyu 82.0000 2.0000 20.0000 60.0000
zhangfei 60.0000 0.0000 0.0000 60.0000
zhugeliang 34.0000 18.0000 16.0000 0.0000

#include <bits/stdc++.h>
using namespace std;
typedef struct hero{
    char name[20];
    int num;
    double zy,dy,wy,sum;
}hero;
hero a[100000];
bool cmp(hero a,hero b)
{
	if(a.sum!=b.sum)	return a.sum>b.sum;		//先按照总分排序 
	if(a.zy!=b.zy)		return a.zy>b.zy;		//总分相同,按智育排序 
	if(a.dy!=b.dy)		return a.dy>b.dy;		//智育相同,按德育排序 
						return a.wy>b.wy; 		//德育相同,按武育排序 
} 
int main()
{
    int t,n;
    double b,c,d;
    while(cin >> t){
        for(int i=0;i<t;i++){
            cin >> n >> b >> c >> d;
            for(int j=0;j<n;j++){
                cin >> a[j].name >> a[j].zy >> a[j].dy >> a[j].wy;
                a[j].num=i+1;
                a[j].zy*=c/100;a[j].dy*=b/100;a[j].wy*=d/100;	//计算折合过的分数
                a[j].sum=a[j].zy+a[j].dy+a[j].wy;				//计算总分
            }
            sort(a,a+n,cmp);
            printf("Case #%d:\n",a[i].num);
            for(int j=0;j<n;j++)
                printf("%s %.4f %.4f %.4f %.4f\n",a[j].name,a[j].sum,a[j].zy,a[j].dy,a[j].wy);
        }
    }
    return 0;
}

这题有一个坑,加权的比率不是a%,b%,c%,而是b%,a%,c%,导致我第一次直接WA。

nefu 874 相约摩洛哥

Description
2015年5月ACM全球总决赛在摩洛哥卡萨布兰卡举行,到时会有来自世界各地的acm大牛齐聚摩洛哥。
作为本次大赛的举办方负责人阿焜和阿祥被分配给了一个重要的任务,就是在比赛中统计大家的排名。
acm大赛排名规则(摘自百度百科):
最后的获胜者为正确解答题目最多且总用时最少的队伍。每道试题用时将从竞赛开始到试题解答被判定为正确为止,其间每一次提交运行结果被判错误的话将被加罚20分钟时间,未正确解答的试题不记时。例如:A、B两队都正确完成两道题目,其中A队提交这两题的时间分别是比赛开始后1:00和2:45,B队为1:20和2:00,但B队有一题提交了2次。这样A队的总用时为1:00+2:45=3:45而B队为1:20+2:00+0:20=3:40,所以B队以总用时少而获胜。
请你帮他俩完成这项任务吧!(保证没有成绩完全相同两支队伍)
Input
多组输入,每组一个正整数n(1<=n<=100000),代表有n个队伍参赛。接下来的n行,每行分别有一个字符串(只包含小写英文字母)作为队伍名,长度1<=len<=10;ABC三道题的ac时间(以分钟为单位),时间为-1表示该题没有ac。接下来又有n行,表示每道题的提交次数,用3个正整数表示。
Output
输出排行榜。n行,每行一个队伍的名字、解题数和总用时。
Sample Input
3
team 30 10 20
behappy 20 20 90
newbee 15 16 17
1 1 1
1 1 10
1 1 1
Sample Output
newbee 3 48
team 3 60
behappy 3 310

#include <bits/stdc++.h>
using namespace std;
typedef struct team{
    char name[10];
    int a[3],b[3];
    int time,ac;
}team;
team q[100000];
bool cmp(team a,team b)	//先按ac的题目数排序,再按照罚时排序
{
    if(a.ac==b.ac)	return a.time<b.time;
    else			return a.ac>b.ac;
}
int main()
{
    int n;
    while(cin >> n){
        for(int i=0;i<n;i++)
            cin >> q[i].name >> q[i].a[0] >> q[i].a[1] >> q[i].a[2];
        for(int i=0;i<n;i++)
            cin >> q[i].b[0] >> q[i].b[1] >> q[i].b[2];
        for(int i=0;i<n;i++){
            q[i].time=q[i].ac=0;
            for(int j=0;j<3;j++){
                if(q[i].a[j]!=-1){		//题目要求若时间不为-1,则表示这题ac
                    q[i].time+=q[i].a[j];
                    q[i].time+=20*(q[i].b[j]-1);
                    q[i].ac++;
                }
            }
        }
        sort(q,q+n,cmp);
        for(int i=0;i<n;i++)
            cout << q[i].name << " " << q[i].ac << " " << q[i].time << endl;
    }
    return 0;
}

题目复杂了些,但并不难。

nefu 1297 结构体排序题一

Description
现在给定一组二维平面上面的点的坐标,保证它的坐标是int类型的整数且大于等于0小于等于99.请你按照数据所给要求进行排序.
首先先以横坐标进行排序,若横坐标相同则按纵坐标排序,降序或升序将以0和1的形式表示,0表示降序,1表示升序.
比如,若数据开头给出0 1的要求,则表示先以横坐标降序排列,若横坐标相同则按纵坐标升序排列.
再比如,若数据开头给出1 1的要求,则表示先以横坐标升序排列,若横坐标相同则按纵坐标升序排列.
保证点的数量大于等于3小于等于99
Input
第1行包含三个数字,第一个数字和第二个数字分别表示横坐标和纵坐标的排序要求,0表示降序,1表示升序,第三个数字n表示有几个点需要排序.
余下第2~n+1行每行各有两个类型为n个点的坐标,例如第2行第一个数字表示第一个点横坐标,第二个数字表示第一个点的纵坐标.
Output
输出n行坐标,一行表示一个点,格式如下:
(x0,y0)
Sample Input
0 0 4
1 1
1 2
2 1
2 2
1 1 4
2 2
2 1
1 2
1 1
Sample Output
(2,2)
(2,1)
(1,2)
(1,1)
(1,1)
(1,2)
(2,1)
(2,2)

#include <bits/stdc++.h>
using namespace std;
typedef struct point{
    int x,y;
}point;
point z[100];
//四个函数均为先按x排序,再按y排序
bool cmp1(point a,point b)	//按照x升序,y升序排序
{
    if(a.x==b.x)	return a.y<b.y;
    else			return a.x<b.x;
}
bool cmp2(point a,point b)	//按照x升序,y降序排序
{
    if(a.x==b.x)	return a.y>b.y;
    else			return a.x<b.x;
}
bool cmp3(point a,point b)	//按照x降序,y升序排序
{
    if(a.x==b.x)	return a.y<b.y;
    else			return a.x>b.x;
}
bool cmp4(point a,point b)	//按照x降序,y降序排序
{
    if(a.x==b.x)	return a.y>b.y;
	else			return a.x>b.x;
}
int main()
{
    int a,b,n;
    while(cin>> a >> b >> n){
        for(int i=0;i<n;i++)
            cin >> z[i].x >> z[i].y;
        if(a==0&&b==0)
            sort(z,z+n,cmp4);
        if(a==0&&b==1)
            sort(z,z+n,cmp3);
        if(a==1&&b==0)
            sort(z,z+n,cmp2);
        if(a==1&&b==1)
            sort(z,z+n,cmp1);
        for(int i=0;i<n;i++)
            printf("(%d,%d)\n",z[i].x,z[i].y);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值