题目描述:
小红一共有 n 个盒子,标号为 1 到 n,小红向盒子里放入小球 m 次,每次进行以下两个操作中的一个:
- 向编号为 x 的盒子里放入一个小球;
- 向除了编号为 x 的其他 n−1 盒子里放入一个小球。
小红想知道,第几次操作之后,所有盒子里至少都有一个小球,如果一直无法达到这个目标,输出 −1。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
输入描述:
第一行两个整数 n 和 m,表示盒子的数量和操作的次数。
接下来 m 行,每行两个整数 t_i 和 x_i,表示第 i 次操作的类型和 x 的值。
1 <= n, m <= 10^5
1 <= t_i <= 2
1<= x_i <= n
输出描述:
输出一个整数,表示第几次操作之后,所有盒子里至少都有一个小球,如果一直无法达到这个目标,输出 -1。
示例1:
输入例子:
3 3
1 1
1 2
1 3
输出例子:
3
例子说明:
三次操作之后,所有盒子里都至少有一个小球。
示例2:
输入例子:
3 4
1 1
2 2
1 3
1 2
输出例子:
4
例子说明:
第一次操作后,盒子 1 里有小球。
第二次操作后,盒子 1、3、4 里有小球。
第三次操作后,盒子 1、3、4 里有小球。
第四次操作后,每个盒子里都有小球。
解题思路:
使用两个unordered_set <int> op1, op2;
t_i代表第i次操作的类型,总共就有两个类型 1 和 2;
如果是类型1,那就把盒子编号x放入op1里,表示编号为x的盒子中已经放了小球了;
如果是类型2,那就把盒子编号x放入op2里,表示在除了编号为x的盒子中都放了小球了;
更具体一些:
如果是第1种类型,t = 1,它代表向编号为 x 的盒子里放入一个小球,那么把x插入到op1里面,表明编号为x的盒子中已经有小球了。
这个时候我们要检查op1的大小是否为盒子总数n,如果是n那么就代表所有的盒子已经满了。因为unordered_set 里面是不允许有重复元素的,它的大小为n,那肯定就是从1到n了(因为盒子的范围就是从1到n)。
此外还有一种情况,如果在op2中有这个元素也代表满了,这是什么意思呢?在op2中存放的编号表示除了这个编号之外的所有盒子编号都放了球,假设t = 1时, x = 2,表示在2号盒子中放入一个小球,那如果x也在op2中,表示除了2号盒子之外的盒子都已经有球了,这样也就是所有的盒子都有球了。
如果是第2种类型,t = 2,代表向除了编号为 x 的其他 n−1 盒子里放入一个小球。把x插入到op2里面。
此时如果op2中的元素个数大于1,则代表满了。比如说原来op2中有一个元素2,它表示除了2号盒子之外都放了一个小球,此时如果在有一个元素放进来,比如4,表示除了4号盒子之外都放了小球,当然前一个空的2号盒子也放了小球,这样所有盒子都放了小球;
还有一种情况,如果op2中原来为空,插入了第一个元素x,如果op1中也有这个元素的话,也代表满了。这一点很好理解,比如说原来op2中有一个元素2,它表示除了2号盒子之外都放了一个小球,2号盒子是空的,如果op1中有2,表示之前已经在op1中放小球了。
如果满的话会输出操作次数然后返回。如果for循环结束了,还没有返回则代表没有满,输出-1;
参考代码:
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
unordered_set<int> op1, op2;
for (int i = 1; i <= m; i++) {
int t, x;
cin >> t >> x;
if (t == 1) {
op1.insert(x);
if (op1.size() == n || op2.find(x) != op2.end()) {
cout << i << endl;
return 0;
}
} else {
op2.insert(x);
if (op2.size() > 1 || op1.find(x) != op1.end()) {
cout << i << endl;
return 0;
}
}
}
cout << -1 << endl;
return 0;
}
还有一种实现方式供参考,超时了,或者有什么好的改进方法欢迎评论区留言:
#include <iostream>
#include <unordered_set>
int main() {
int n, m;
std::cin >> n >> m;
std::unordered_set<int> mySet;
for (int i = 1; i <= n; ++i) {
mySet.insert(i);
}
int i;
for (i = 1; i <= m; ++i) {
int operation;
std::cin >> operation;
if (operation == 1) {
int num;
std::cin >> num;
mySet.erase(num);
if (mySet.empty()) {
break;
}
} else {
int x;
std::cin >> x;
if (mySet.find(x) == mySet.end()) {
break;
}
mySet.clear();
mySet.insert(x);
}
}
std::cout << (i > m ? -1 : i) << std::endl;
return 0;
}