灵动ICPC冬令营基础-5

A - Brainman

题目

Background
Raymond Babbitt drives his brother Charlie mad. Recently Raymond counted 246 toothpicks spilled all over the floor in an instant just by glancing at them. And he can even count Poker cards. Charlie would love to be able to do cool things like that, too. He wants to beat his brother in a similar task.

Problem
Here’s what Charlie thinks of. Imagine you get a sequence of N numbers. The goal is to move the numbers around so that at the end the sequence is ordered. The only operation allowed is to swap two adjacent numbers. Let us try an example:
Start with: 2 8 0 3
swap (2 8) 8 2 0 3
swap (2 0) 8 0 2 3
swap (2 3) 8 0 3 2
swap (8 0) 0 8 3 2
swap (8 3) 0 3 8 2
swap (8 2) 0 3 2 8
swap (3 2) 0 2 3 8
swap (3 8) 0 2 8 3
swap (8 3) 0 2 3 8

So the sequence (2 8 0 3) can be sorted with nine swaps of adjacent numbers. However, it is even possible to sort it with three such swaps:
Start with: 2 8 0 3
swap (8 0) 2 0 8 3
swap (2 0) 0 2 8 3
swap (8 3) 0 2 3 8

The question is: What is the minimum number of swaps of adjacent numbers to sort a given sequence?Since Charlie does not have Raymond’s mental capabilities, he decides to cheat. Here is where you come into play. He asks you to write a computer program for him that answers the question. Rest assured he will pay a very good prize for it.
Input
The first line contains the number of scenarios.
For every scenario, you are given a line containing first the length N (1 <= N <= 1000) of the sequence,followed by the N elements of the sequence (each element is an integer in [-1000000, 1000000]). All numbers in this line are separated by single blanks.
Output
Start the output for every scenario with a line containing “Scenario #i:”, where i is the number of the scenario starting at 1. Then print a single line containing the minimal number of swaps of adjacent numbers that are necessary to sort the given sequence. Terminate the output for the scenario with a blank line.
Sample Input

4
4 2 8 0 3
10 0 1 2 3 4 5 6 7 8 9
6 -42 23 6 28 -100 65537
5 0 0 0 0 0

Sample Output

Scenario #1:
3

Scenario #2:
0

Scenario #3:
5

Scenario #4:
0

解析

• 对于序列中的一个数,前面大于它的和后面小于它的数的个数,就是该数的逆序对数。一个序列的逆序对数就是该序列的所有数的逆序对数的总和。
• 本题要求计算,对一个给出的序列进行排序,相邻数字的最小互换次数。也就是要求计算一个序列的逆序对数。
• 可以用归并排序计算逆序对数,在归并排序中的交换次数就是这个序列的逆序对数:归并排序是将序列a[l, r]分成两个序列a[l, m]和a[m+ 1, r],分别进行归并排序,然后再将这两个有序序列进行归并排序,在归并排序的过程中,设l<=i<=m,m+1<=j<=r,a[i]<=a[j]时,并不产生逆序对数;而当a[i]> a[j]时,则在有序列a[l, m]中,在a[i]后面的数都比a[j]大,将a[j]放在a[i]前,逆序对数就要加上m-i+1。因此,可以在归并排序的合并过程中计算逆序对数。

代码

#include <cstdio>
const int max=1008;
int a[max], tmp[max];
int ans;
void Merge(int l, int m, int r) {
    
    
    int i=l;
    int j=m+1;
    int k=l;
    while(i<=m&&j<=r) {
    
    
        if(a[i]>a[j]) {
    
    
            tmp[k++]=a[j++];
            ans+=m-i+1;
        }
        else {
    
    
            tmp[k++]=a[i++];
        }
    }
    while(i<=m) tmp[k++]=a[i++];
    while(j<=r) tmp[k++]=a[j++];
    for(int i=l;i<=r;i++) a[i]=tmp[i];
}
void Merge_sort(int l,int r) {
    
    
    if(l<r) {
    
    
        int m=(l+r)>>1;
        Merge_sort(l, m);
        Merge_sort(m+1, r);
        Merge(l, m, r);
    }
}
int main() {
    
    
    int t, n, f=1, i;
    scanf("%d", &t);
    while(t--) {
    
    
        scanf("%d",&n);
        for(i=0;i<n;i++) scanf("%d", &a[i]);
        ans=0;
        Merge_sort(0, n-1);
        printf("Scenario #%d:\n%d\n\n", f++, ans);
    }
    return 0;
}

B - Ultra-QuickSort

题目

在这里插入图片描述

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
9 1 0 5 4
Ultra-QuickSort produces the output
0 1 4 5 9
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 – the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.
Output
For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
Sample Input

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0

解析

对于本题,如果用两重循环枚举序列的每个数对(Ai,Aj),其中i<j,检验Ai是否大于Aj,然后统计逆序对数。这种算法虽然简洁,时间复杂度为O(n2),由于本题的输入序列的长度n<500,000,当n很大时,相应的程序出解非常慢。
所以,本题和上一题【Brainman】一样,利用时间复杂度为O(nlog2n)的归并排序求逆序对数。

代码

#include <cstdio>
const int max=500008;
long long a[max], tmp[max];
long long ans;
void Merge(int l, int m, int r) {
    
    
    int i=l;
    int j=m+1;
    int k=l;
    while(i<=m&&j<=r) {
    
    
        if(a[i]>a[j]) {
    
    
            tmp[k++]=a[j++];
            ans+=m-i+1;
        }
        else {
    
    
            tmp[k++]=a[i++];
        }
    }
    while(i<=m) tmp[k++]=a[i++];
    while(j<=r) tmp[k++]=a[j++];
    for(int i=l;i<=r;i++) a[i]=tmp[i];
}
void Merge_sort(int l,int r) {
    
    
    if(l<r) {
    
    
        int m=(l+r)>>1;
        Merge_sort(l, m);
        Merge_sort(m+1, r);
        Merge(l, m, r);
    }
}
int main() {
    
    
    int n, i, t;
    while(scanf("%d", &n)&&n) {
    
    
    	ans=0;
    	for(i=0;i<n;i++) scanf("%lld", &a[i]);
        	Merge_sort(0, n-1);
        	printf("%lld\n", ans);
	}
    return 0;
}

C - Who’s in the Middle

题目

FJ is surveying his herd to find the most average cow. He wants to know how much milk this ‘median’ cow gives: half of the cows give as much or more than the median; half give as much or less.

Given an odd number of cows N (1 <= N < 10,000) and their milk output (1…1,000,000), find the median amount of milk given such that at least half the cows give the same amount of milk or more and at least half give the same or less.
Input

  • Line 1: A single integer N
  • Lines 2…N+1: Each line contains a single integer that is the milk output of one cow.
    Output
  • Line 1: A single integer that is the median milk output.
    Sample Input
5
2
4
1
3
5

Sample Output

3

Hint
INPUT DETAILS:
Five cows with milk outputs of 1…5
OUTPUT DETAILS:
1 and 2 are below 3; 4 and 5 are above 3.

解析

快速排序是对冒泡排序的一种改进:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
对n个数进行排序,然后输出前m个大的数。由于数据规模很大,采用时间复杂度为O(n2)的排序算法有可能会超时。所以本题采用快速排序来对n个数进行排序。

代码

#include <cstdio>
#include <algorithm>
const int N=10008;
int a[N];
void quick_sort(int a[], int p, int q) {
    
    
	int i = p, j = q, m = a[p+q >> 1], t;
	while (i <= j) {
    
    
		while (a[i] < m) ++i;
		while (a[j] > m) --j;
		if (i <= j) std::swap(a[i++], a[j--]);
	}
	if (p < j) quick_sort(a, p, j);
	if (i < q) quick_sort(a, i, q);
}
int main() {
    
    
    int t, n, f=1, i;
    scanf("%d",&n);
    for(i=0;i<n;i++) scanf("%d", &a[i]);
    quick_sort(a, 0, n-1);
    printf("%d", a[n/2]);
    return 0;
}

D - Word AmalgamationSquares

题目

In millions of newspapers across the United States there is a word game called Jumble. The object of this game is to solve a riddle, but in order to find the letters that appear in the answer it is necessary to unscramble four words. Your task is to write a program that can unscramble words.
Input
The input contains four parts: 1) a dictionary, which consists of at least one and at most 100 words, one per line; 2) a line containing XXXXXX, which signals the end of the dictionary; 3) one or more scrambled ‘words’ that you must unscramble, each on a line by itself; and 4) another line containing XXXXXX, which signals the end of the file. All words, including both dictionary words and scrambled words, consist only of lowercase English letters and will be at least one and at most six characters long. (Note that the sentinel XXXXXX contains uppercase X’s.) The dictionary is not necessarily in sorted order, but each word in the dictionary is unique.
Output
For each scrambled word in the input, output an alphabetical list of all dictionary words that can be formed by rearranging the letters in the scrambled word. Each word in this list must appear on a line by itself. If the list is empty (because no dictionary words can be formed), output the line “NOT A VALID WORD” instead. In either case, output a line containing six asterisks to signal the end of the list.
Sample Input

Sample Input

tarp
given
score
refund
only
trap
work
earn
course
pepper
part
XXXXXX
resco
nfudre
aptr
sett
oresuc
XXXXXX

Sample Output

score
******
refund
******
part
tarp
trap
******
NOT A VALID WORD
******
course
******

解析

设字典表示为字符数组s。在字典被输入后,字典s就被建立了。然后,对于每个在s中的单词s [i],通过选择排序,完成word的字典序排列。
接下来,依次输入待处理的单词,每输入一个单词存入字符串a,通过sort函数,对其按字符升序进行排序;然后和s中的单词s[i]逐个比较:s[i]也通过sort函数按字符升序进行排序,如果两者相等,输出s [i];比较结束时,没有相等的情况,则输出"NOT A VALID WORD"。
在参考程序中,字符串比较函数strcmp按字典序比较两个字符串,并返回结果:如果两个字符串相等,则返回零;字符串复制函数strcpy则是将源字符串变量的内容复制到目标字符串变量中。

代码

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int main() {
    
    
    char s[108][10], a[10], b[10];
    int i, j, t=0, l1, l2, f;
    while(1){
    
    
        scanf("%s", s[t]);
        if(strcmp(s[t++], "XXXXXX") == 0) break;
    }
    for(i=0;i<t-2;i++) {
    
    
    	for(j=i+1;j<t-1;j++) {
    
    
        	if(strcmp(s[i], s[j])>0) {
    
    
                strcpy(a, s[i]);
                strcpy(s[i], s[j]);
                strcpy(s[j], a);
            }
		}
	}
    while(scanf("%s", a)!=EOF&&strcmp(a,"XXXXXX")!=0) {
    
    
        f=1;
        for(i=0;i<t-1;i++) {
    
    
            l1=strlen(a);
            l2=strlen(s[i]);
            strcpy(b, s[i]);
            sort(a, a+l1);
            sort(b, b+l2);
            if(strcmp(b, a)==0) {
    
    
                printf("%s\n", s[i]);
                f=0;
            }
        }
        if(f) printf("NOT A VALID WORD\n");
        printf("******\n");
    }
    return 0;
}

E - 排名

题目

今天的上机考试虽然有实时的Ranklist,但上面的排名只是根据完成的题数排序,没有考虑
每题的分值,所以并不是最后的排名。给定录取分数线,请你写程序找出最后通过分数线的考生,并将他们的成绩按降序打印。
Input
测试输入包含若干场考试的信息。每场考试信息的第1行给出考生人数N ( 0 < N< 1000 )、考题数M ( 0 < M < = 10 )、分数线(正整数)G;第2行排序给出第1题至第M题的正整数分值;以下N行,每行给出一名考生的准考证号(长度不超过20的字符串)、该生解决的题目总数m、以及这m道题的题号(题目号由1到M)。当读入的考生人数为0时,输入结束,该场考试不予处理。
Output
对每场考试,首先在第1行输出不低于分数线的考生人数n,随后n行按分数从高到低输出上线考生的考号与分数,其间用1空格分隔。若有多名考生分数相同,则按他们考号的升序输出。
Sample Input

4 5 25
10 10 12 13 15
CS004 3 5 1 3
CS003 5 2 4 1 3 5
CS002 2 1 2
CS001 3 2 3 5
1 2 40
10 30
CS001 1 2
2 3 20
10 10 10
CS000000000000000001 0
CS000000000000000002 2 1 2
0

Sample Output

3
CS003 60
CS001 37
CS004 37
0
1
CS000000000000000002 20

Hint
Huge input, scanf is recommended.

解析

设考生序列为s,考生用结构表示,其中字符数组c表示考号,sum表示解决的题目总数,score表示分数。
首先,在输入每个考生信息的时候,根据解题的题号,统计考生的分数。然后结构体排序,分数和考号分别为第一和二关键字。
最后,按题目要求输出不低于分数线的考生人数,以及分数线上的考生信息。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1008;
struct Data{
    
    
	char c[28];
	int sum;
	int score;
}s[N];
bool cmp(Data x, Data y) {
    
    
	if(x.score!=y.score)
	return x.score>y.score;
	else return strcmp(x.c,y.c)<0;
}
int main() {
    
    
	int n, m, g, p[18], k, count, id, i, j;
	char x[28];
	while(~scanf("%d", &n)&&n) {
    
    
		id=0;
		scanf("%d%d", &m, &g);
		for(i=1;i<=m;i++) {
    
    
			scanf("%d", &p[i]);
		}
		for(i=0;i<n;i++) {
    
    
			count=0;
			scanf("%s %d", x, &s[i].sum);
			for(j=0;j<s[i].sum;j++) {
    
    
				scanf("%d", &k);
				count+=p[k];
			}
			if(count>=g) {
    
    
				strcpy(s[id].c, x);
				s[id].score=count;
				id++;
			}	
		}
		sort(s, s+id, cmp);
		if(id==0) printf("0\n");
		else {
    
    
			printf("%d\n",id);
			for(int i=0;i<id;i++) {
    
    
				printf("%s %d\n", s[i].c, s[i].score);
			}
		}
	}
    return 0;
}

F - Election Time

题目

The cows are having their first election after overthrowing the tyrannical Farmer John, and Bessie is one of N cows (1 ≤ N ≤ 50,000) running for President. Before the election actually happens, however, Bessie wants to determine who has the best chance of winning.
The election consists of two rounds. In the first round, the K cows (1 ≤ K ≤ N) cows with the most votes advance to the second round. In the second round, the cow with the most votes becomes President.
Given that cow i expects to get Ai votes (1 ≤ Ai ≤ 1,000,000,000) in the first round and Bi votes (1 ≤ Bi ≤ 1,000,000,000) in the second round (if he or she makes it), determine which cow is expected to win the election. Happily for you, no vote count appears twice in the Ai list; likewise, no vote count appears twice in the Bi list.
Input

  • Line 1: Two space-separated integers: N and K
  • Lines 2…N+1: Line i+1 contains two space-separated integers: Ai and Bi
    Output
  • Line 1: The index of the cow that is expected to win the election.
    Sample Input
5 3
3 10
9 2
5 6
8 4
6 5

Sample Output

5

解析

用一个结构体数组表示n头竞选总统的奶牛,在结构体中,给出一头奶牛的第一轮预期得票,第二轮预期得票,以及这头奶牛的编号。
求解本题,则要进行两次排序。第一次,n头奶牛第一轮预期得票排序;第二次,在第一次排序的前k头奶牛的第二轮预期得票排序。最后,输出第二轮中票数最多的牛的编号。

代码

#include <stdio.h>
#include <algorithm>
const int N=50008;
using namespace std;
struct Data{
    
    
    int id, v1, v2;
}a[N];
bool cmp1(Data a, Data b){
    
    
    return (a.v1>b.v1);
}
bool cmp2(Data a, Data b){
    
    
    return (a.v2>b.v2);
}
int main(){
    
    
    int n, k, i;
    scanf("%d%d", &n, &k);
    for (i=0;i<n;i++){
    
    
        scanf("%d%d", &a[i].v1, &a[i].v2);
        a[i].id=i+1;
    }
    sort(a, a+n,cmp1);
    sort(a, a+k,cmp2);
    printf("%d\n", a[0].id);
    return 0;
}

G - Holiday Hotel

题目

Mr. and Mrs. Smith are going to the seaside for their holiday. Before they start off, they need to choose a hotel. They got a list of hotels from the Internet, and want to choose some candidate hotels which are cheap and close to the seashore. A candidate hotel M meets two requirements:
Any hotel which is closer to the seashore than M will be more expensive than M.
Any hotel which is cheaper than M will be farther away from the seashore than M.
Input
There are several test cases. The first line of each test case is an integer N (1 <= N <= 10000), which is the number of hotels. Each of the following N lines describes a hotel, containing two integers D and C (1 <= D, C <= 10000). D means the distance from the hotel to the seashore, and C means the cost of staying in the hotel. You can assume that there are no two hotels with the same D and C. A test case with N = 0 ends the input, and should not be processed.
Output
For each test case, you should output one line containing an integer, which is the number of all the candidate hotels.
Sample Input

5
300 100
100 300
400 200
200 400
100 500
0

Sample Output

2

解析

设宾馆序列为a,宾馆用结构表示,其中第i家宾馆离海滩的距离为a[i].jl,住宿费用为a[i].fy。根据侯选宾馆的需求,以离海滩距离为第1关键字、住宿费用为第2关键字,对结构数组h进行排序。然后,在此基础上计算侯选宾馆的数目f:对于已经排序的结构数组a,根据题意,如果宾馆a的jl比宾馆b小,那么b的fy一定要比a的fyt小,这样b才能作为候选宾馆,以此,依次扫描每家宾馆:若当前宾馆i虽然离海滩的距离不近但费用低,则宾馆i进入候选序列,f++。最后输出侯选宾馆的数目f。

代码

#include <cstdio>
#include <algorithm>
const int N=10008;
using namespace std;
struct Data{
    
    
    int fy;
    int jl;
}a[N];
bool cmp(Data a, Data b){
    
    
    if(a.jl!=b.jl) return (a.jl<b.jl);
    else return (a.fy<b.fy);
}
int main(){
    
    
    int n, i, t, f, p;
    while(scanf("%d", &n)&&n) {
    
    
    	f=0;p=N;
    	for(i=0;i<n;i++) {
    
    
    		scanf("%d %d", &a[i].jl, &a[i].fy);
		}
		sort(a, a+n, cmp);	
		for(i=0;i<n;i++) {
    
    
			if(a[i].fy<p)  ++f, p=a[i].fy;
		}
		printf("%d\n", f);
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_52328032/article/details/112988498