牛客周赛 Round 56 (A - E)

传送门

A - 面包店故事

原题

小镇上有一家面包店,面包以 x 元的价格出售,加 y 元可以多加几块培根。小歪带着 n 元来到了面包店,他想知道自己能不能买到加培根的面包?

输入

在一行上输入三个整数 x , y , n x,y,n x,y,n ( 1 ≤ x , y , n ≤ 100 1≤x,y,n≤100 1x,y,n100) 代表面包的价格、培根的价格和小歪带的钱。

输出

如果小歪能加到培根,在一行上输出 YES ;否则,直接输出 NO 。

测试样例

Input 1
3 1 5
Output 1
YES

Input 2
10 1 10
Output 2
NO

分析

  • 小歪要想买到能加培根的面包,那么小歪的钱就必须大于等于面包加培根的钱,即 n ≥ x + y n \ge x + y nx+y
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

//std::mt19937 rng {std::chrono::steady_clock::now().time_since_epoch().count()};

int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int x, y, n;
	std::cin >> x >> y >> n;
	if(n >= x + y) {
		std::cout << "YES";
	} else {
		std::cout << "NO";
	}

	return 0;
}

B - 放课后的故事

原题

小 S 想要举办一个纸飞机大赛,他最新研制出的纸飞机需要 k 张纸才能折成。 为了制作纸飞机,他向班里的 n 个人要了一些纸,第 i 个人提供了 ai 张纸给小 S 研究纸飞机。 放学了,小 S 终于折好了全部的纸飞机,现在有 m 个人留下来和小 S一起飞纸飞机。最多有多少个人能分到纸飞机。

输入

第一行输入三个整数 n , m , k n, m, k n,m,k( 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105, 1 ≤ m ≤ 1 0 5 1 \le m \le 10^5 1m105, 1 ≤ k ≤ 1 0 9 1 \le k \le 10^9 1k109) 代表班级同学数量、留下来的同学数量和叠一只纸飞机需要的纸的数量。
第二行输入 n n n 个整数 a 1 a_{1} a1, a 2 a_{2} a2,… a n a_{n} an ( 1 ≤ a i ≤ 1 0 9 1 \le a_{i} \le 10^9 1ai109)代表每一个同学提供的纸的数量

输出

在一行上输出一个整数,代表最多有多少个人能分到纸飞机。

测试样例

Input 1
3 2 5
1 2 4
Output 1
1

Input 2
6 3 4
1 1 4 5 1 4
Output 2
4

分析

  • n个同学每个人都给了小S一定数量的纸,而折一个纸飞机需要k张纸,那么可得出小S用这些纸折了多少纸飞机,然后再用这些纸飞机与留下来的同学个数 +1(小S自己) 取最小即可
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;



int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int n, m, k;
	std::cin >> n >> m >> k;
	std::vector<int> a(n);
	for(int i = 0; i < n; i++) {
		std::cin >> a[i];
	}
	i64 sum = std::accumulate(all(a), 0LL);	//计算a数组 + 0 的和
	i64 cnt = sum / k;
	std::cout << std::min<i64>(cnt, m);

	return 0;
}

C - 异或故事

原题

给定 t 组询问,76 每次询问都会给出一个正整数 a ,你需要在区间 [1,10^9] 中找到两个正整数 b 和 c ,使得 b ⊕ c = a 。⊕ 代表按位异或。

输入

每个测试文件均包含多组测试数据。第一行输入一个整数 T T T ( 1 ≤ T ≤ 1 0 5 1 \le T \le 10^5 1T105) 代表数据组数,每组测试数据描述如下:
在一行上输入一个整数 a a a ( 1 ≤ a ≤ 1 0 9 1 \le a \le 10^9 1a109) 代表76 给出的初始数字.

输出

对于每一组测试数据,在一行上输出两个正整数,代表你找到的两个值。
如果存在多个解决方案,您可以输出任意一个。

测试样例

Input 1
3
1
5
4
Output 1
2 3
3 6
74 78

分析

  • 这一题考察到了位运算,如果对位运算不了解,可以先去学习一下位运算

  • 题目给的初始数字最大为 1 0 9 10^9 109,而 int 的最大值是大于这个数的,所以我们可以放心的用int来做题

  • 对任一数据 a a a,在二进制下,由一定的 1 1 1 表示,例如 ( 10 ) 10 (10)_{10} (10)10 = ( 1010 ) 2 (1010)_{2} (1010)2 , ( 16 ) 10 (16)_{10} (16)10 = ( 10000 ) 2 (10000)_{2} (10000)2

  • 那么对于按位异或运算:

  • 如果 a a a 在二进制下 1 1 1 的个数 ≥ 2 \ge 2 2 个,那么我们可以直接取一个 1 1 1 b b b,然后把剩余的 1 1 1 c c c,那么 一定就有 b ⊕ c = a b ⊕ c = a bc=a
    在这里插入图片描述

  • 如果 a a a 在二进制下 1 1 1 的个数 = 1 =1 =1,,那么我们为了保留这个 1 1 1,同时其他位为 0 0 0 且保证 b , c ∈ [ 1 , 1 0 9 ] b, c \in [1, 10^9] b,c[1,109],可以使 b = a + 1 b = a + 1 b=a+1 c = 1 c = 1 c=1
    在这里插入图片描述

  • 注意,这里要特判一下 a = 1 a = 1 a=1的情况,因为 2 ⊕ 1 = 3 2⊕1 = 3 21=3

#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;



void solve() {
	i64 a;
	std::cin >> a;

	if(a == 1) {
		std::cout << 2 << " " << 3 << "\n";
	} else {
		if(__builtin_popcount(a) == 1) {	//统计a在二进制下1的个数
			std::cout << 1 << " " << a + 1 << "\n";
		} else {
			i64 ans = 0;
			for(int i = 0; i < 30; i++) {
				if((1LL << i) & a) {
					ans += 1LL << i;
					break;
				}
			}
			std::cout << ans << " " << a - ans << "\n";
		}
	}
}

int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	i64 t;
	std::cin >> t;
	while(t--) {
		solve();
	}


	return 0;
}

D - 构造故事

原题

小 S 今天在数学课上学习了三角形,他回家立马拿出了自己的 n 根火柴,想知道从这 n 根火柴中任选 3 根,能否组成一个周长最大的三角形。
由于小 S 只会暴力枚举,所以他把这个问题交给了你,你能帮他解决这个问题吗?

输入

每个测试文件均包含多组测试数据。第一行输入一个整数 T T T ( 1 ≤ T ≤ 20 ) ( 1 \leq T \leq 20) (1T20)代表数据组数,每组测试数据描述如下:
第一行输入一个整数 n ( 3 ≤ n ≤ 1 0 4 ) n (3 \leq n \leq 10^4) n(3n104) 代表小S的火柴数量。
第二行输入 n n n 个整数 a 1 , a 2 , . . . a n ( 1 ≤ a i ≤ 1 0 9 ) a_{1}, a_{2},...a_{n} (1 \leq a_{i} \leq 10^9) a1,a2,...an(1ai109)代表每根火柴的长度

输出

对于每一组测试数据,在一行上输出一个整数,代表能组成周长最大三角形的周长;如果无论如何都无法组成三角形,直接输出 −1 。

测试样例

Input 1
3
6
2 2 10 4 10 6
5
6 1 5 3 3
5
2 2 4 10 6
Output 1
26
14
-1

分析

  • 要构造一个三角形,那么就有两边之和 > > > 第三边,对于给定的边,我们可以对其先排序,然后从大开始找(因为要求的是周长最长的三角形),假设三条边按从小到大为 a , b , c a, b, c a,b,c,如果 a , b , c a, b, c a,b,c能构成三角形,那么直接输出 a + b + c a + b + c a+b+c即可,如果不行,那么一定有 a + b < c a + b < c a+b<c,此时我们只能往前找,为什么?因为 a + b a + b a+b 一定是当前最大的两边之和了,如果让另外的边来替换,那么仍然是 < c < c <c的,是不满足题意的,所以只需要往前遍历,如果最终都没能构成三角形,输出 -1即可
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;



void solve() {
	int n;
	std::cin >> n;
	std::vector<int> a(n + 1);
	for(int i = 1; i <= n; i++) {
		std::cin >> a[i];
	}
	std::sort(a.begin() + 1, a.end());	//排序,注意a.begin() + 1
	for(int i = n - 2; i >= 0; i--) {
		i64 t1 = a[i], t2 = a[i + 1], t3 = a[i + 2];	//三条边
		if(t1 + t2 > t3) {
			std::cout << t1 + t2 + t3 << "\n";
			return;
		}
	}
	std::cout << "-1\n";
}

int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int t;
	std::cin >> t;
	while(t--) {
		solve();
	}

	return 0;
}

E - 约会故事

由于该题题目过长,请大家直接点击链接查看原题

分析

  • 首先对输入进行处理,我们可以把一整天的每个时间点看作 24 ∗ 60 24 * 60 2460 个点,因此输入就是一个区间修改,可以使用差分来进行处理
  1. 当输入的第二个时间点小于等于第一个时间点时,说明小C一整天都是开心的,因此设置 s s 1 = 0 ss1 = 0 ss1=0 s s 2 = 24 ∗ 60 ss2 = 24 *60 ss2=2460,然后设置 s u m [ s s 1 ] + + , s u m [ s s 2 + 1 ] − − sum[ss1]++, sum[ss2 + 1]-- sum[ss1]++,sum[ss2+1]即可完成区间修改,
  2. 当输入的第二个时间点大于第一个时间点时,说明小C在 s s 1 → s s 2 ss1 \to ss2 ss1ss2时间内是开心的,同1理设置差分数组sum
  • 对于奶茶的名字,我们可以使用C++内置的map来进行管理(具体细节请看代码,很好理解)
  • 对于查询,首先要确定发送消息的时间 00 : 00 → 01 : 59 00:00 \to 01:59 00:0001:59,即 s s 1 ≤ 120 ss1 \le 120 ss1120,或者 s u m [ s s 1 ] = 1 sum[ss1] = 1 sum[ss1]=1(这是一个单点查询),然后再去判断是否比小C提前来到电影院并且是否带对了奶茶,如果这些条件均满足,则可输出 " W i n n e r   x q q " "Winner \space xqq" "Winner xqq",否则输出 " J o k e r   x q q " "Joker \space xqq" "Joker xqq"
#include<bits/stdc++.h>
#define all(a) a.begin(), a.end()
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

int sum[24 * 60 + 5];
int main() {
	
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	int n, m;
	std::cin >> n >> m;
	
	for(int i = 0; i < n; i++) {
		std::string s;
		std::cin >> s;
		int hh = ((s[0] - '0') * 10 + (s[1] - '0'));
		int mm = ((s[3] - '0') * 10 + (s[4] - '0'));
		int ss1 = hh * 60 + mm;
		std::cin >> s;
		hh = ((s[0] - '0') * 10 + (s[1] - '0'));
		mm = ((s[3] - '0') * 10 + (s[4] - '0'));
		int ss2 = hh * 60 + mm;
		if(ss1 >= ss2) {
			ss1 = 0;
			ss2 = 24 * 60;
		}
		sum[ss1]++;
		sum[ss2 + 1]--;
	}
	for(int i = 1; i <= 24 * 60; i++) {
		sum[i] += sum[i - 1];
	}
	std::map<std::string, int> mp;
	for(int i = 0; i < m; i++) {
		std::string s;
		std::cin >> s;
		mp[s] = 1;
	}
	int q;
	std::cin >> q;
	for(int i = 0; i < q; i++) {
		int ok = 1;
		std::string s1, s2, s3, s4;
		std::cin >> s1 >> s2 >> s3 >> s4;
		int hh1 = ((s1[0] - '0') * 10 + (s1[1] - '0'));
		int mm1 = ((s1[3] - '0') * 10 + (s1[4] - '0'));
		int ss1 = hh1 * 60 + mm1;
		int hh2 = ((s2[0] - '0') * 10 + (s2[1] - '0'));
		int mm2 = ((s2[3] - '0') * 10 + (s2[4] - '0'));
		int ss2 = hh2 * 60 + mm2;
		int hh3 = ((s3[0] - '0') * 10 + (s3[1] - '0'));
		int mm3 = ((s3[3] - '0') * 10 + (s3[4] - '0'));
		int ss3 = hh3 * 60 + mm3;
		if(sum[ss1] == 0) {
			ok = 0;
		}
		if(ss1 >= 120) {
			ok = 0;
		}
		if(!ok) {
			std::cout << "Loser xqq\n";
			continue;
		}
		if(ss2 > ss3) {
			ok = 0;
		}
		if(!mp.count(s4)) {
			ok = 0;
		}
		if(ok) {
			std::cout << "Winner xqq\n";
		} else {
			std::cout << "Joker xqq\n";
		}

	}

	return 0;
}

以上。
文章参考的资源,特此鸣谢
1位运算全面总结,关于位运算看这篇就够了
2前缀和与差分 图文并茂 超详细整理(全网最通俗易懂)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值