2021-01-22总结

2021-01-22总结

今天在家没事,下午用了不到三个小时把之前缺课落下的第二章—数据排序的题给做完了。
这九道题总体来说做的还是挺顺利的,除了第九题一开始忘记把横坐标减掉 i 之后再排一遍顺序,导致样例虽然过了,但是提交 luogu WA 了三个点,其他题做得还不错,就相当于复习了一遍各种排序方法(其实我就用到了sort,桶排和冒泡排序)。

1、明明的随机数(Noip2006)
【问题描述】
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到
1000 之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对
应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明
完成“去重”与“排序”的工作。
【输入文件】
输入文件 random.in 有 2 行,
第 1 行为 1 个正整数,表示所生成的随机数的个数:N
第 2 行有 N 个用空格隔开的正整数,为所产生的随机数。
【输出文件】
输出文件 random.out 也是 2 行,第 1 行为 1 个正整数 M,表示不相同的随机数的个数。第 2 行为 M 个
用空格隔开的正整数,为从小到大排好序的不相同的随机数。
【输入样例】
10
20 40 32 67 40 20 89 300 400 15
【输出样例】
8
15 20 32 40 67 89 300 400

#include
using namespace std;
int n,a[1005],b[105],sum,q=1;
int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		int k;
		scanf("%d",&k);
		a[k]++;
	}
	for(int i=1;i<=1005;i++){
     
		if(a[i]!=0){
     
			sum++;
			b[q]=i;
			q++;
		}
	}
	printf("%d\n",sum);
	for(int i=1;i<=q-1;i++){
     
		printf("%d ",b[i]);
	}
	return 0;
}
/*
10
20 40 32 67 40 20 89 300 400 15
*/ 
 

2、车厢重组(carry)
【问题描述】
在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的
长度最多能容纳两节车厢,如果将桥旋转 180 度,则可以把相邻两节车厢的位置交换,用这种方法可以重
新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。他退休后,火车站决定
将这一工作自动化,其中一项重要的工作是编一个程序,输入初始的车厢顺序,计算最少用多少步就能将
车厢排序。
【输入文件】
输入文件有两行数据,第一行是车厢总数 N(不大于 10000),第二行是 N 个不同的数表示初始的车厢
顺序。
【输出文件】
一个数据,是最少的旋转次数。
【输入样例】
4
4 3 2 1
【输出样例】
6

#include
using namespace std;
int n,a[10001],step;
int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n-1;i++){
     
		for(int j=1;j<=n-1;j++){
     
			if(a[j]>a[j+1]){
     
				++step;
				int mid=a[j];
				a[j]=a[j+1];
				a[j+1]=mid;
			}
		}
	}
	printf("%d",step);
	return 0;
}
/*
4
4 3 2 1 
*/ 

3、众数(masses)
【问题描述】
由文件给出N个1到 30000 间无序数正整数,其中 1≤N≤10000,同一个正整数可能会出现多次,出
现次数最多的整数称为众数。求出它的众数及它出现的次数。
【输入格式】
输入文件第一行是正整数的个数 N,第二行开始为 N 个正整数。
【输出格式】
输出文件有若干行,每行两个数,第 1 个是众数,第 2 个是众数出现的次数。
【输入样例】
12
2 4 2 3 2 5 3 7 2 3 4 3
【输出样例】
2 4
3 4

#include
using namespace std;
int maxn,sum[101],n,a[30001];
int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		int k;
		scanf("%d",&k);
		a[k]++;
	} 
	for(int i=1;i<=30001;i++){
     
		if(maxn<a[i]){
     
			maxn=a[i];
		}
	}
	int q=1;
	for(int i=1;i<=30001;i++){
     
		if(a[i]==maxn){
     
			sum[q]=i;
			q++;
		}
	}
	for(int i=1;i<=q-1;i++){
     
		printf("%d %d\n",sum[i],maxn);
	}
	return 0;
}
/*
12
2 4 2 3 2 5 3 7 2 3 4 3 
*/

4、第 k 小整数(knumber)
【问题描述】
现有 n 个正整数,n≤10000,要求出这 n 个正整数中的第 k 个最小整数(相同大小的整数只计算一次),
k≤1000,正整数均小于 30000。
【输入格式】
第一行为 n 和 k,第二行开始为 n 个正整数的值,整数间用空格隔开。
【输出格式】
第 k 个最小整数的值;若无解,则输出“NO RESULT”。
【输入样例】
10 3
1 3 3 7 2 5 1 2 4 6
【输出样例】
3

#include
using namespace std;
int n,k,b[30005],sum;
int main()
{
     
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
     
        int a;
		scanf("%d",&a);
        b[a]++;
    }
    for(int i=1;i<=30000;i++){
     
        if(b[i]>=1){
     
        	sum++;	
		}
        if(sum==k){
     
			printf("%d",i);
			return 0;
		}
    }
    printf("NO RESULT");
    return 0;
}
/*
10 3
1 3 3 7 2 5 1 2 4 6
*/

5、军事机密(secret)
【问题描述】
军方截获的信息由 n(n<=30000)个数字组成,因为是敌国的高端秘密,所以一时不能破获。最原始
的想法就是对这 n 个数进行从小到大排序,每个数都对应一个序号,然后对第 i 个是什么数感兴趣,现在
要求编程完成。
【输入格式】
第一行 n,接着是 n 个截获的数字,接着一行是数字 k,接着是 k 行要输出数的序号。
【输出格式】
k 行序号对应的数字。
【输入样例】
5
121 1 126 123 7
3
2
4
3
【输出样例】
7
123
121

#include
using namespace std;
int main()
{
     
	int n,k,a[30005],b[30005];
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		scanf("%d",&a[i]);
	}
	scanf("%d",&k);
	for(int i=1;i<=k;i++){
     
		scanf("%d",&b[i]);
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=k;i++){
     
		printf("%d\n",a[b[i]]);
	} 
	return 0;
}
/*
5
121 1 126 123 7
3
2
4
3 
*/ 

6、奖学金(Noip2007)
【问题描述】
某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前 5 名学生发奖学金。期末,每
个学生都有 3 门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语
文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面,这样,每
个学生的排序是唯一确定的。
任务:先根据输入的 3 门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前 5 名学生
的学号和总分。注意,在前 5 名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。
例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分)是:
7 279
5 279
这两行数据的含义是:总分最高的两个同学的学号依次是 7 号、5 号。这两名同学的总分都是 279(总
分等于输入的语文、数学、英语三科成绩之和),但学号为 7 的学生语文成绩更高一些。如果你的前两名的
输出数据是:5 279
7 279
则按输出错误处理,不能得分。
【输入格式】
输入文件 scholar.in 包含 n+1 行:
第 1 行为一个正整数 n,表示该校参加评选的学生人数。
第2到 n+1 行,每行有 3 个用空格隔开的数字,每个数字都在 0 到 100 之间。第 j 行的 3 个数字依次
表示学号为 j-1 的学生的语文、数学、英语的成绩。每个学生的学号按照输入顺序编号为 1~n(恰好是输
入数据的行号减 1)。 所给的数据都是正确的,不必检验。
【输出格式】
输出文件 scholar.out 共有 5 行,每行是两个用空格隔开的正整数, 依次表示前 5 名学生的学号和总
分。
【输入输出样例 1】
scholar.in scholar.out
6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98
6 265
4 264
3 258
2 244
1 237
【输入输出样例 2】
scholar.in scholar.out
8
80 89 89
88 98 78
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98
8 265
2 264
6 264
1 258
5 258
【限制】
50%的数据满足:各学生的总成绩各不相同
100%的数据满足:6<=n<=300

#include
using namespace std;
int n;
struct cwy{
     
	int id,ch,ma,en,tot;
}a[305];
bool cmp(cwy x,cwy y){
     
	if(x.tot!=y.tot)
		return x.tot>y.tot;
	else{
     
		if(x.ch!=y.ch)
			return x.ch>y.ch;
		else{
     
			return x.id<y.id;		
		}	
	}
}
int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		scanf("%d%d%d",&a[i].ch,&a[i].ma,&a[i].en);
		a[i].tot=a[i].ch+a[i].ma+a[i].en;
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=5;i++){
     
		printf("%d %d\n",a[i].id,a[i].tot);
	}
	return 0;
} 
/*
6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98 
*/ 

7、统计数字(Noip2007)
【问题描述】
某次科研调查时得到了n个自然数,每个数均不超过 1500000000(1.5109
)。已知不相同的数不超过
10000 个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。
【输入格式】
输入文件 count.in 包含 n+1 行:
第 1 行是整数 n,表示自然数的个数。
第 2~n+1 行每行一个自然数。
【输出格式】
输出文件 count.out 包含 m 行(m 为 n 个自然数中不相同数的个数),按照自然数从小到大的顺序输出。
每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。
【输入输出样例】
count.in count.out
8
2
4
2
4
5
100
2
100
2 3
4 2
5 1
100 2
【限制】
40%的数据满足:1<=n<=1000
80%的数据满足:1<=n<=50000
100%的数据满足:1<=n<=200000,每个数均不超过 1 500 000 000(1.5
109

#include
using namespace std;
long long p=1,n;
struct cwy{
     
	long long num,times;
}a[20001];
bool cmp(cwy x,cwy y){
     
	return x.num<y.num;
}
int main()
{
     
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
     
		int k,flag=0;
		scanf("%lld",&k);
		for(int i=1;i<=p-1;i++){
     
			if(a[i].num==k){
     
				flag=1;
				a[i].times++;
				break;
			}
		}
		if(flag==0){
     
			a[p].num=k;
			a[p].times++;
			p++;
		}
	}
	sort(a+1,a+p,cmp);
	for(int i=1;i<=p-1;i++){
     
		printf("%lld %lld\n",a[i].num,a[i].times);
	}
	return 0;
}
/*
8
2
4
2
4
5
100
2
100 
*/

8、输油管道问题(pipe)
【问题描述】
某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n 口油井的油田。从每口油井
都要有一条输油管道沿最短路径(或南或北)与主管道相连。如果给定n口油井的位置,即它们的x 坐标(东
西向)和y 坐标(南北向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总
和最小的位置?证明可在规定时间内确定主管道的最优位置。
【编程任务】
给定n 口油井的位置,编程计算各油井到主管道之间的输油管道最小长度总和。
【输入格式】
第1 行是油井数n,1≤n≤10000。接下来n 行是油井的位置,每行2个整数x和y,-10000≤x,y≤10000。
【输出格式】
第1 行中的数是油井到主管道之间的输油管道最小长度总和。
【输入样例】
5
1 2
2 2
1 3
3 -2
3 3
【输出样例】
6

#include
using namespace std;
int n,x[10005],y[10005],ans;
int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		scanf("%d%d",&x[i],&y[i]);
	}
	sort(y+1,y+n+1);
	for(int i=1;i<=n/2;i++){
     
		ans+=y[n-i+1]-y[i];
	}
	printf("%d",ans);
	return 0;	
}
/* 
5
1 2
2 2
1 3
3 -2
3 3
*/

9、士兵站队问题
【问题描述】
在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点由整数坐标(x,y)表示。士兵们可
以沿网格边上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士
兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何选择x 和y的值才能使士兵
们以最少的总移动步数排成一列。
【编程任务】
计算使所有士兵排成一行需要的最少移动步数。
【输入格式】
第1 行是士兵数n,1≤n≤10000。接下来n 行是士兵的初始位置,每行2 个整数x 和y,-10000≤x,
y≤10000。
【输出格式】
第1 行中的数是士兵排成一行需要的最少移动步数。
【输入样例】
5
1 2
2 2
1 3
3 -2
3 3
【输出样例】
8

#include
using namespace std;
int n,x[10005],y[10005],ans1,ans2,ans;
int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
     
		scanf("%d%d",&x[i],&y[i]);
	}
	sort(y+1,y+n+1);
	for(int i=1;i<=n;i++){
     
		ans1+=abs(y[(n+1)/2]-y[i]);
	}
	sort(x+1,x+n+1);
	for(int i=1;i<=n;i++){
     
		x[i+1]-=i;
	}
	sort(x+1,x+n+1);
	for(int i=1;i<=n;i++){
     
		ans2+=abs(x[(n+1)/2]-x[i]);
	}
	ans=ans1+ans2;
	printf("%d",ans);
	return 0;
}
/*
5
1 2
2 2
1 3
3 -2
3 3
*/ 

你可能感兴趣的:(2021-01-22总结)