校内训练赛题解第三篇

人气估值

题目描述
你是某动画制作公司的企划部长。如今动画制作公司制作的东西,已经不仅仅局限于动画本身。相关商品,例如登场人物的手办和人物歌曲CD等,也是重要的收益来源。这个收益能提高到什么程度,完全取决于作为企划部长的你。
这是理所当然的,但这些相关产品并不是随便推出就可以的。因为开发商品需要大量的时间和预算。即使要发售动画中登场人物的手办,也必须限定于销售额高、人气高的人物。
衡量角色人气度的手段之一,就是人气投票。到目前为止,你也策划了几场人气投票,看来观众已经逐渐对这个策划不满了。当务之急是建立其他衡量受欢迎程度的方法。
所以你提出了一个假设。一个角色的受欢迎程度,与其在动画正编中的登场时间的总和成正比。为了验证这个假设,你决定编写一个程序来统计每个角色的出场时间。

输入
输入由多个情况组成。每个情况以以下格式给出。

n
name0 m0 d0,0 … d0,m0-1
name1 m1 d1,0 … d1,m1-1
.
.
.
namen-1 mn-1 dn-1,0 … dn-1,mn-1-1
n表示角色的人数。name
i

表示角色的名字。
m
i

表示人物出现的时间次数。m
i

后面是m
i

个整数d
i,j


d
i,j

表示人物出现的时间。

输入的结尾由n=0的行给出

如果在某一时刻只有一个角色出现在屏幕上,则该角色可以获得n点。
在同一时间出现的角色每增加一个,在该时间出现的角色所获得的点数减少1。
如果有n个角色在同一时间出现,则n个角色分别加1分。
输入满足以下条件。
2≤n≤20
0≤m
i

≤30
0≤d
i,j

<30
第i个字符的d
i,j

都不一样。
name
i

只包含大写或小写字母,长度不超过10。(小于等于10)

输出
把点数最小的角色的点数和那个名字用一个空白隔开输出。
如果有多个角色的点数最小,名字按字典顺序选择最小的人。

解题思路

看清题目。。。。 这题思路很简单,我们用一个map数组记录一下每一个数字出现的次数。那么对于第i个人我们在计算第j天的时候就加上 n - cd[a[j]] + 1 即可

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
using namespace std;
const int N = 110;

int n ;
struct node {
	string name;
	int a[N], cnt;
	int pot;
	bool operator < (const node &w)const {
		if (pot == w.pot)
			return name < w.name;
		return pot < w.pot;
	}
};


int main() {
	while (cin >> n, n) {
		map<int, int>cd;
		node p[N];
		for (int i = 1 ; i <= n ; ++i) {
			cin >> p[i].name >> p[i].cnt;
			for (int j = 0 ; j < p[i].cnt; ++j) {
				cin >> p[i].a[j];
				cd[p[i].a[j]]++;
			}
		}
		for (int i = 1 ; i <= n ; ++i) {
			int c = 0 ;
			for (int j = 0 ; j < p[i].cnt ; ++j) {
				int x = n - cd[p[i].a[j]];
				c += ++x;
			}
			p[i].pot = c;
		}
		sort(p + 1, p + 1 + n);
		cout << p[1].pot << ' ' << p[1].name << endl;
	}
	return 0;
}

脑力训练计划 (模拟 + 字符串)

题面
她很烦恼。成绩不好。虽然她勉强要求父母让自己上了全寄宿制学校,但她的才华却丝毫没有绽放。也许他本来就没有天赋,但这是她尽可能不愿意去想的可能。
于是,她依赖在网上找到的诡异脑力训练教材。训练教材上说,通过用手解决类似补充可能性问题的实例,计算力得到提高,进而逻辑性思考力、直觉力、想象力也变得丰富,社团活动也活跃起来,恋爱也顺利进行。这诱惑着她学习这个教材。
根据教材描述,必须对加法范式表示的逻辑表达式的各个变量进行适当分配,判断逻辑表达式的值是否可以为真。顺便提一下,一个以上的变量(或者,其否定)的逻辑积称为从句(clause),只有几个从句的逻辑和表示的逻辑表达式遵循加法标准形式。一般说到补充可能性问题,逻辑表达式用乘法标准形来表示,但要注意,训练计划是加法标准形态。
她想研究一下训练计划的问题集,然后突然改变了主意。与其花钱买一本习题,不如请一个擅长编程的好朋友吃一顿冻糕,让他生成训练计划问题,并编写一个解决问题的程序。这样岂不是就可以得到很多问题和答案了吗。就这样,作为她最好的朋友,请你写一个解决训练计划的程序。

输入
输入由多个数据组成。每个情况以以下格式给出。

表达式字符串
输入的结尾由“#”组成的行给出
表达式遵循以下规则:

::= “(”")" | “(”")|("")"
::= “&”"&"
::= | “~”
::= [a-z]|[A-z]
(在这里,字符串文本用双引号括了起来。实际输入不包含双引号。)
此外,输入中没有多余的空格。
注意,从句由三个字面量组成。
表达式的长度不得超过500个字符。
测试用例的数量不超过1100个。

输出
如果存在使给定表达式的值为真的变量分配,则输出yes,否则输出no。

解题思路

  1. 难点一: 读入的问题: 判断结束每一个数据的标志,我们用pre记录当前字符的前一个字符。如果前一个字符是)而当前字符不是|就表明到了数据的结尾,那么就应该输出一个结果出来。
  2. 难点二:判断表达式。由于是或运算,因此我们记录在所有的子表达式中(括号中)如果能会真那么整个结果就可以为真。那么什么时候子表达式不能会真呢?就是对于同一个字符它的否和它本身同时存在。(因为括号内是与运算)有一个为假就肯定会假。因此我们在一个子表达式结束的时候(字符为))的时候,看如果没有上面说的情况说明至少有一个为真,那么就满足条件了。那么如何实现呢?
  3. 我们以一个子表达式为单位,对于每一个字符统计其出现的次数,如果是重复出现的,那么与第一次的前一个字符进行对比。

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
using namespace std;
const int N = 1e4 + 10;
char st[N]; // 记录子表达式中同一个字符的第一个前字符

int main() {
	char ch, pre = ' ' ;
	bool flag = false,  key = true;
	int c = 0;
	map<char, int>cnt; // 统计字符出现的次数
	while (cin >> ch, pre != '#') {
		if (pre == ')' && ch != '|') {
			if (c)
				cout << "yes" << endl;
			else
				cout << "no" << endl;
			cnt.clear();
			c = 0;
		}
		if (isalpha(ch)) {
			if (cnt.count(ch) && (pre == '~' && st[ch] != '~') || (pre != '~' && st[ch] == '~')) {
				key = false;
			} else if (cnt.count(ch) == 0)
				cnt[ch]++, st[ch] = pre;
		}
		if (ch == ')') {
			if (key)
				c ++;
			key = true;
			memset(st, 0, sizeof st);
			cnt.clear();
		}
		pre = ch;
	}
	return 0;
}

大暑赛期(贪心 + 思维)

题目描述
目前,人们的娱乐仅限于编程竞赛。教练一直在征集试题,这些试题分为|Math|Greedy|Geometry|DP|Graph|Other|六类。
好在收集到了很多问题,教练就想多开几场比赛。比赛由三道题组成,为了让比赛更具教育意义,教练决定举办以下四种比赛。
1、数学竞赛:Math试题和DP试题共3道题
2、算法游戏大赛:Greedy题和Graph题共3道题
3、实现游戏竞赛:Geometry问题和Other问题共3道题
4、均衡竞赛:一套三道题:1道来自Math或DP,1道来自Greedy或Graph,1道来自Geometry或Other

当然,在某项比赛中出题的题目是不能在其他比赛中出题的。教练的愿望是举办尽可能多的比赛。我们知道6类试题的数量,那么,最多能开几次竞赛呢?

输入
输入由多个情况组成。每个情况以以下格式给出。
n
Math

n
Greedy

n
Geometry

n
DP

n
Graph

n
Other

各输入值表示各类型问题的库存数量。
当输为0 0 0 0 0 0时,表示样例数据结束。

每个值满足以下条件
n
Math

+n
Greedy

+n
Geometry

+n
DP

+n
Graph

+n
Other

≤10
8

此外,测试用例的数量不超过20,000个。

输出
在一行中输出可能的最大竞赛数。

解题思路:

  1. 对于两种方法。我们发现0与3,1与4和2与5 是可以合在一起看的(数据从下标0开始算的话)
  2. 合并完,那么对于这三个数,我们有两种方式,一个是前各自除以3,然后再进行另一种方式,一组挑一个数。对于这个方法,在经过n多次的找规律的时候,发现:如果这三个数有两个数能整除3,另外一个数求余三的结果<= 1那么使用这个方法是最优的。如6 4 6如果我们先减去最小值。那么变为2 0 2那么最终次数就是4 ,不过如果我们先除以3,变为0 1 0结果是5.之所以另外一个数余3结果是<= 1是因为如果是0的话,肯定是先除以三,对于余1这个很关键,这个1的作用是好比上面的例子减去4后变为2 0 2那么如果我们返回一次,每个数都加上1变为3 1 3那么两个三各自除以3,就从1次变成了两次。明显更优。
  3. 对于另外一种方式。先减去最小值,再各次除以三。提供剩余的有出现2 0 2的情况我们就用类似上面的方式回一次。加上一。(这个的条件是减去的最小值不能是0)如2 0 2

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
LL a[7];

int main() {
	while (cin >> a[0] >> a[1] >> a[2] >> a[3] >> a[4] >> a[5], a[0] || a[4] || a[1] || a[2] || a[3] || a[5] ) {
		LL res = 0;
		LL n1 = a[0] + a[3], n2 = a[1] + a[4], n3 = a[2] + a[5];
		LL minx =  min(n1, min(n2, n3));
		if ((n1 % 3 == 0 && (n2 % 3 ) <= 1 && n3 % 3 == 0) || (n2 % 3 == 0 && (n1 % 3 ) && n3 % 3 == 0) || (n1 % 3 == 0
		        && (n3 % 3 ) <= 1 && n2 % 3 == 0) ) {
			res += n1 / 3 + n2 / 3 + n3 / 3;
			n1 %= 3, n2 %= 3, n3 %= 3;
			while (n1 && n2 && n3) {
				res ++ ;
				n1 --, n2--, n3--;
			}
		} else {
			bool flag = true;
			if (minx == 0)
				flag = false;
			res += minx;
			n1 -= minx, n2 -= minx, n3 -= minx;
			res += n1 / 3 + n2 / 3 + n3 / 3;
			n1 %= 3, n2 %= 3, n3 %= 3;
			if (flag && ((n1 == 2 && n2 == 2) || (n1 == 2 && n3 == 2) || (n2 == 2 && n3 == 2)))
				res ++;
		}
		cout << res << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值