7-1 统计工龄
给定公司N名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。
输入格式:
输入首先给出正整数N(≤105),即员工总人数;随后给出N个整数,即每个员工的工龄,范围在[0, 50]。
输出格式:
按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为0则不输出该项。
输入样例:
8
10 2 0 5 7 2 5 2
输出样例:
0:1
2:3
5:2
7:1
10:1
#include<bits/stdc++.h>
using namespace std;
const int N = 55;
int cnt[N];
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++){
int year;
cin >> year;
cnt[year]++;
}
for(int i = 0; i <= 50; i++){
if(cnt[i]){
cout << i << ":" << cnt[i] << endl;
}
}
return 0;
}
7-2 寻找大富翁
胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。
输入格式:
输入首先给出两个正整数N(≤106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。
输出格式:
在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。
输入样例:
8 3
8 12 7 3 20 9 5 18
输出样例:
20 18 12
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
long long int a[N];
int main()
{
int n, m;
cin >> n >> m;
for(int i = 0; i < n; i++){
cin >> a[i];
}
sort(a, a + n);
if(m > n){
m = n;
}
for(int i = n - 1; i >= n - m; i--){
printf("%lld%c", a[i], i == n - m ? '\n' : ' ');
}
return 0;
}
7-3 点赞狂魔
微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。
输入格式:
输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name
K F1⋯FK”,其中Name
是不超过8个英文小写字母的非空用户名,1≤K≤1000,Fi(i=1,⋯,K)是特性标签的编号,我们将所有特性标签从 1 到 107 编号。数字间以空格分隔。
输出格式:
统计每个人点赞的不同标签的数量,找出数量最大的前3名,在一行中顺序输出他们的用户名,其间以1个空格分隔,且行末不得有多余空格。如果有并列,则输出标签出现次数平均值最小的那个,题目保证这样的用户没有并列。若不足3人,则用-
补齐缺失,例如mike jenny -
就表示只有2人。
输入样例:
5
bob 11 101 102 103 104 105 106 107 108 108 107 107
peter 8 1 2 3 4 3 2 5 1
chris 12 1 2 3 4 5 6 7 8 9 1 2 3
john 10 8 7 6 5 4 3 2 1 7 5
jack 9 6 7 8 9 10 11 12 13 14
输出样例:
jack chris john
#include<bits/stdc++.h>
using namespace std;
const int N = 1e2 + 10;
set<int>s;
struct node{
string name;
int sum;
int cnt;
}like[N];
bool cmp(node a, node b){
if(a.cnt != b.cnt) return a.cnt > b.cnt;
else return a.sum < b.sum;
}
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++){
cin >> like[i].name >> like[i].sum;
for(int j = 0; j < like[i].sum; j++){
int x;
cin >> x;
s.insert(x);
}
like[i].cnt = s.size();
s.clear();
}
sort(like, like + n, cmp);
int i = 0;
for(; i < 3 && i < n; i++){
if(i == 0) cout << like[i].name;
else cout << ' ' << like[i].name;
}
for(; i < 3; i++){
cout << ' ' << '-';
}
}
7-4 插入排序还是归并排序
根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?
输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。
输出格式:
首先在第 1 行中输出Insertion Sort
表示插入排序、或Merge Sort
表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。
输入样例 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
输出样例 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
输入样例 2:
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
输出样例 2:
Merge Sort
1 2 3 8 4 5 7 9 0 6
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N], ans[N];
int main()
{
int n, range = 2;
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
for(int j = 0; j < n; j++){
cin >> ans[j];
}
int i, j;
for(i = 1; i < n; i++){
if(ans[i] < ans[i-1]){
break;
}
}
for(j = i; j < n; j++){
if(ans[j] != a[j]){
break;
}
}
if(j < n){
cout << "Merge Sort" << endl;
while(1){
for(i = 0; i < n; i++){
if(ans[i] != a[i]){
break;
}
}
for(j = 0; j < n / range; j++){
sort(a+j*range, a+(j+1)*range);
}
sort(a+n/range*range, a+n);
if(i == n) break;
range *= 2;
}
}
else{
cout << "Insertion Sort" << endl;
sort(a, a+i+1);
}
for(i = 0; i < n; i++){
if(i == 0) cout << a[i];
else cout << ' ' << a[i];
}
return 0;
}
7-5 插入排序还是堆排序
根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
堆排序也是将输入分为有序和无序两部分,迭代地从无序部分找出最大元素放入有序部分。它利用了大根堆的堆顶元素最大这一特征,使得在当前无序区中选取最大元素变得简单。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?
输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。
输出格式:
首先在第 1 行中输出Insertion Sort
表示插入排序、或Heap Sort
表示堆排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。
输入样例 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
输出样例 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
输入样例 2:
10
3 1 2 8 7 5 9 4 6 0
6 4 5 1 0 3 2 7 8 9
输出样例 2:
Heap Sort
5 4 3 1 0 2 6 7 8 9
#include<bits/stdc++.h>
#define INF 99999999
using namespace std;
int n;
int before[110];
int after[110];
int sorted[110];
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) {
scanf("%d",&before[i]);
sorted[i]=before[i];
}
for(int i=0;i<n;i++) scanf("%d",&after[i]);
int count1=0,count2=0;
for(int i=0;i<=n;i++){
if(after[i]>after[i+1]){
count1=i;
break;
}
}
for(int i=count1+1;i<n;i++){
if(before[i]==after[i]){
count2++;
}else break;
}
if(count2+count1+1==n){
printf("Insertion Sort\n");
sort(after,after+count1+2);
for(int i=0;i<n-1;i++)
printf("%d ",after[i]);
printf("%d\n",after[n-1]);
}
else{
printf("Heap Sort\n");
int a=n-1;
while(after[a]>after[0]) a--;
swap(after[a],after[0]);
int low=0,high=1;
while(high<a){
if(high+1<a&&after[high]<after[high+1])high++;
if(after[low]>after[high])break;
swap(after[low],after[high]);
low=high;high=low*2+1;
}
for(int i=0;i<n-1;i++)
printf("%d ",after[i]);
printf("%d\n",after[n-1]);
}
return 0;
}
7-6 逆序对
求逆序对。
输入格式:
第一行是一个整数n,(n<=1000,000)表示输入序列的长度,接下来一行是n个整数(每个数的绝对值小于109)。
输出格式:
一个数,表示逆序对个数(逆序即任意一对数前面的数比后面的数大即为一对逆序对)。
输入样例:
10
1 3 5 7 9 8 4 2 6 10
输出样例:
逆序对对数可能很大,计数器要用long long:
14
说明:样例中如1和3不是逆序对,而3和2是1对逆序对,例子中共有14对逆序对。题目中可能有某些数字出现多次的情况。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
ll cnt;
int a[N], c[N];
void merge(int s, int e){
if(s == e) return ;
int mid = s + e >> 1;
merge(s, mid);
merge(mid + 1, e);
int i = s, j = mid + 1, k = s;
while(i <= mid && j <= e){
if(a[i] <= a[j]){
c[k++] = a[i++];
}
else{
c[k++] = a[j++];
cnt += mid -i + 1;
}
}
while(i <= mid) c[k++] = a[i++];
while(j <= e) c[k++] = a[j++];
for(int i = s; i <= e; i++){
a[i] = c[i];
}
}
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
merge(1, n);
cout << cnt << endl;
return 0;
}
7-7 堆排序
给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。
输出格式:
对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。
输入样例:
4
8 7 2 1
输出样例:
7 1 2 8
2 1 7 8
1 2 7 8
#include<bits/stdc++.h>
using namespace std;
void HeapAdjust(int* a, int i, int n)
{
int lchild = 2 * i;
int rchild = 2 * i + 1;
int max = i;
if (i <= n / 2) {
if (lchild <= n && a[lchild] > a[max])
max = lchild;
if (rchild <= n && a[rchild] > a[max])
max = rchild;
if (max != i) {
swap(a[i], a[max]);
HeapAdjust(a, max, n);
}
}
}
void BuildHeap(int* a, int n)
{
for (int i = n / 2; i >= 1; i--){
HeapAdjust(a, i, n);
}
}
void HeapSort(int* a, int n)
{
BuildHeap(a, n);
for (int i = n; i > 1; i--){
swap(a[1], a[i]);
HeapAdjust(a, 1, i - 1);
for (int j = 1; j <= n; j++){
if (j == 1)
cout << a[j];
else
cout << " " << a[j];
}
cout << endl;
}
}
int main()
{
int a[100], n;
while (~scanf("%d", &n)){
for (int i = 1; i <= n; i++)
cin >> a[i];
HeapSort(a, n);
}
return 0;
}
7-8 石子合并
由n堆石子排成一排,其编号为1,2,3……,n。每堆石子有一定的质量mi(mi<=1000),现在要将这n堆石子合并成一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,由于合并顺序的不同,导致合并成一堆石子的总代价也不同,请求出最少的代价将所有石子合并为一堆。
输入格式:
第一行输入n。
第二行输入n个mi。
输出格式:
输出一个整数,表示石子合并的最小代价。
输入样例:
4
2 5 3 1
输出样例:
22
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 210;
int a[N], sum[N], f[N][N];
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum[i] = sum[i-1] + a[i];
}
memset(f, INF, sizeof(f));
for(int len = 1; len <= n; len++){
for(int i = 1; i + len - 1 <= n; i++){
int j = i + len - 1;
if(len == 1) f[i][j] = 0;
else{
for(int k = i; k < j; k++){
f[i][j]=min(f[i][j], f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
}
}
}
}
cout << f[1][n] << endl;
return 0;
}
7-9 第k小
有n个数,求第k小的数。例如在数:{1 3 5 7 9 8 4 2 6 10}中,第3小的数是3 。
输入格式:
第一行输入两个数,n和k(n<=1000000),分别表示总的n个数和求第k小的数。第二行输入n个数( 最大数<10^7)。
输出格式:
一个数,表示第k小的数。
输入样例:
在这里给出一组输入。例如:
10 3
1 3 5 7 9 8 4 2 6 10
输出样例:
在这里给出相应的输出。例如:
3
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
}
sort(a, a + n);
printf("%d", a[k-1]);
}
7-10 快速排序的过程
给定n个整型元素,利用快速排序算法对其进行非递减排序,请输出每一趟Partition的结果。每次选择所处理的区间的第一个元素作为基准元素。
输入格式:
输入为两行,第一行为一个整数n(1<n≤1000),表示元素个数。第二行为n个空格间隔的整数,表示待排序的元素。
输出格式:
输出为若干行,每行依次输出Partition后的结果,每个元素后一个空格。
输入样例:
5
4 5 3 2 1
输出样例:
2 1 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
#include<bits/stdc++.h>
using namespace std;
int n;
void print(int a[]){
for(int i = 0; i < n; i++){
cout << a[i] <<' ';
}
cout << endl;
}
void Quick_Sort(int a[], int l, int r){
if(l > r) return ;
int i = l, j = r, t = a[l];
while(i < j){
while(a[j] >= t && i < j){
j--;
}
while(a[i] <= t && i < j){
i++;
}
if(i < j){
swap(a[i], a[j]);
}
}
swap(a[l], a[i]);
print(a);
Quick_Sort(a, l, i - 1);
Quick_Sort(a, i+1, r);
}
const int N = 1e3 + 10;
int a[N];
int main(){
cin >> n;
for(int i = 0; i < n; i++){
cin >> a[i];
}
Quick_Sort(a, 0, n - 1);
return 0;
}