NOIP2005年提高组复赛上机试题

A. 谁拿了最多奖学金

某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:

  1. 院士奖学金,每人8000元,期末平均成绩高于80分(>80),并且在本学期内发表1篇或1篇以上论文的学生均可获得;
  2. 五四奖学金,每人4000元,期末平均成绩高于85分(>85),并且班级评议成绩高于80分(>80)的学生均可获得;
  3. 成绩优秀奖,每人2000元,期末平均成绩高于90分(>90)的学生均可获得;
  4. 西部奖学金,每人1000元,期末平均成绩高于85分(>85)的西部省份学生均可获得;
  5. 班级贡献奖,每人850元,班级评议成绩高于80分(>80)的学生干部均可获得;

只要符合条件就可以得奖,每项奖学金的获奖人数没有限制,每名学生也可以同时获得多项奖学金。

例如姚林的期末平均成绩是87分,班级评议成绩82分,同时他还是一位学生干部,那么他可以同时获得五四奖学金和班级贡献奖,奖金总数是4850元。

现在给出若干学生的相关数据,请计算哪些同学获得的奖金总数最高(假设总有同学能满足获得奖学金的条件)。

输入格式
输入文件的第一行是一个整数N,表示学生的总数。

接下来的N行每行是一位学生的数据,从左向右依次是姓名,期末平均成绩,班级评议成绩,是否是学生干部,是否是西部省份学生,以及发表的论文数。

姓名是由大小写英文字母组成的长度不超过20的字符串(不含空格);期末平均成绩和班级评议成绩都是0到100之间的整数(包括0和100);是否是学生干部和是否是西部省份学生分别用一个字符表示,Y表示是,N表示不是;发表的论文数是0到10的整数(包括0和10)。

每两个相邻数据项之间用一个空格分隔。

输出格式
输出文件包括三行,第一行是获得最多奖金的学生的姓名,第二行是这名学生获得的奖金总数。

如果有两位或两位以上的学生获得的奖金最多,输出他们之中在输入文件中出现最早的学生的姓名。

第三行是这N个学生获得的奖学金的总数。

数据范围
1≤N≤100
输入样例:
4

YaoLin 87 82 Y N 0
ChenRuiyi 88 78 N Y 1
LiXin 92 88 N N 0
ZhangQin 83 87 Y N 1

输出样例:

ChenRuiyi
9000
28700

AC代码

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int n;
struct Person
{
    string name;
    int final_score, class_score;
    char is_cadre, is_west;
    int papers;
    int money;
}p[N];

int get_money(Person a)
{
    int res = 0;
    if (a.final_score > 80 && a.papers) res += 8000;
    if (a.final_score > 85 && a.class_score > 80) res += 4000;
    if (a.final_score > 90) res += 2000;
    if (a.final_score > 85 && a.is_west == 'Y') res += 1000;
    if (a.class_score > 80 && a.is_cadre == 'Y') res += 850;
    return res;
}

int main()
{
    cin >> n;
    int sum = 0;
    for (int i = 0; i < n; i ++ )
    {
        cin >> p[i].name;
        cin >> p[i].final_score >> p[i].class_score;
        cin >> p[i].is_cadre >> p[i].is_west;
        cin >> p[i].papers;
        p[i].money = get_money(p[i]);
        sum += p[i].money;
    }
    int t = 0;
    for (int i = 1; i < n; i ++ )
    {
    	if (p[i].money > p[t].money)
    	{
    		t = i;
    	}
    }
    cout << p[t].name << endl;
    cout << p[t].money << endl;
    cout << sum << endl;
    return 0;
}

B. 过河

在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。

在桥上有一些石子,青蛙很讨厌踩在这些石子上。

由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。

座标为0的点表示桥的起点,座标为L的点表示桥的终点。

青蛙从桥的起点开始,不停的向终点方向跳跃。

一次跳跃的距离是S到T之间的任意正整数(包括S,T)。

当青蛙跳到或跳过座标为L的点时,就算青蛙已经跳出了独木桥。

题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。

你的任务是确定青蛙要想过河,最少需要踩到的石子数。

输入格式
输入文件的第一行有一个正整数L,表示独木桥的长度。

第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数。

第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。

所有相邻的整数之间用一个空格隔开。

输出格式
输出文件只包括一个整数,表示青蛙过河最少需要踩到的石子数。

数据范围
1≤L≤109,
1≤S≤T≤10,
1≤M≤100
输入样例:

10
2 3 5
2 3 5 6 7

输出样例:

2

AC代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 10005, M = 110;
int L, S, T, n;
int f[N], w[N], stones[M];
int main()
{
	scanf("%d%d%d%d", &L, &S, &T, &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &stones[i]);
	}
	sort(stones + 1, stones + n + 1);
	if (S == T)
	{
		int res = 0;
		for (int i = 1; i <= n; i++)
		{
			if (stones[i] % S == 0)
			{
				res++;
			}
		}
		printf("%d\n", res);
		return 0;
	}
	for (int i = 1, last = 0, offset = 0; i <= n; i++)
	{
		if (stones[i] - last > 100)
		{
			offset += stones[i] - 100 - last;
		}
		last = stones[i];
		stones[i] -= offset;
	}
	for (int i = 1; i <= n; i++)
	{
		w[stones[i]] = 1;
	}
	L = stones[n] + 10;
	for (int i = 1; i <= L; i++)
	{
		f[i] = 0x3f3f3f3f;
		for (int j = S; j <= T; j++)
		{
			if (i >= j)
			{
				f[i] = min(f[i], f[i - j] + w[i]);
			}
		}
	}
	printf("%d\n", f[L]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章