本文涉及知识点
[CSP-S2020] 动物园
题目描述
动物园里饲养了很多动物,饲养员小 A 会根据饲养动物的情况,按照《饲养指南》购买不同种类的饲料,并将购买清单发给采购员小 B。
具体而言,动物世界里存在 2 k 2^k 2k 种不同的动物,它们被编号为 0 ∼ 2 k − 1 0 \sim 2^k - 1 0∼2k−1。动物园里饲养了其中的 n n n 种,其中第 i i i 种动物的编号为 a i a_i ai。
《饲养指南》中共有 m m m 条要求,第 j j j 条要求形如“如果动物园中饲养着某种动物,满足其编号的二进制表示的第 p j p_j pj 位为 1 1 1,则必须购买第 q j q_j qj 种饲料”。其中饲料共有 c c c 种,它们从 1 ∼ c 1 \sim c 1∼c 编号。本题中我们将动物编号的二进制表示视为一个 k k k 位 01 串,第 0 0 0 位是最低位,第 k − 1 k - 1 k−1 位是最高位。
根据《饲养指南》,小 A 将会制定饲料清单交给小 B,由小 B 购买饲料。清单形如一个 c c c 位 01 01 01 串,第 i i i 位为 1 1 1 时,表示需要购买第 i i i 种饲料;第 i i i 位为 0 0 0 时,表示不需要购买第 i i i 种饲料。 实际上根据购买到的饲料,动物园可能可以饲养更多的动物。更具体地,如果将当前未被饲养的编号为 x x x 的动物加入动物园饲养后,饲料清单没有变化,那么我们认为动物园当前还能饲养编号为 x x x 的动物。
现在小 B 想请你帮忙算算,动物园目前还能饲养多少种动物。
输入格式
第一行包含四个以空格分隔的整数
n
,
m
,
c
,
k
n, m, c, k
n,m,c,k。
分别表示动物园中动物数量、《饲养指南》要求数、饲料种数与动物编号的二进制表示位数。
第二行
n
n
n 个以空格分隔的整数,其中第
i
i
i 个整数表示
a
i
a_i
ai。
接下来
m
m
m 行,每行两个整数
p
i
,
q
i
p_i, q_i
pi,qi 表示一条要求。
数据保证所有
a
i
a_i
ai 互不相同,所有的
q
i
q_i
qi 互不相同。
输出格式
仅一行一个整数表示答案。
样例 #1
样例输入 #1
3 3 5 4
1 4 6
0 3
2 4
2 5
样例输出 #1
13
样例 #2
样例输入 #2
2 2 4 3
1 2
1 3
2 4
样例输出 #2
2
样例 #3
样例输入 #3
见附件中的 zoo/zoo3.in
样例输出 #3
见附件中的 zoo/zoo3.ans
提示
【样例 #1 解释】
动物园里饲养了编号为 1 , 4 , 6 1, 4, 6 1,4,6 的三种动物,《饲养指南》上的三条要求为:
- 若饲养的某种动物的编号的第 0 0 0 个二进制位为 1 1 1,则需购买第 3 3 3 种饲料。
- 若饲养的某种动物的编号的第 2 2 2 个二进制位为 1 1 1,则需购买第 4 4 4 种饲料。
- 若饲养的某种动物的编号的第 2 2 2 个二进制位为 1 1 1,则需购买第 5 5 5 种饲料。
饲料购买情况为:
- 编号为 1 1 1 的动物的第 0 0 0 个二进制位为 1 1 1,因此需要购买第 3 3 3 种饲料;
- 编号为 4 , 6 4, 6 4,6 的动物的第 2 2 2 个二进制位为 1 1 1,因此需要购买第 4 , 5 4, 5 4,5 种饲料。
由于在当前动物园中加入一种编号为 0 , 2 , 3 , 5 , 7 , 8 , … , 15 0, 2, 3, 5, 7, 8, \ldots , 15 0,2,3,5,7,8,…,15 之一的动物,购物清单都不会改变,因此答案为 13 13 13。
【数据范围】
对于
20
%
20 \%
20% 的数据,
k
≤
n
≤
5
k \le n \le 5
k≤n≤5,
m
≤
10
m \le 10
m≤10,
c
≤
10
c \le 10
c≤10,所有的
p
i
p_i
pi 互不相同。
对于
40
%
40 \%
40% 的数据,
n
≤
15
n \le 15
n≤15,
k
≤
20
k \le 20
k≤20,
m
≤
20
m \le 20
m≤20,
c
≤
20
c \le 20
c≤20。
对于
60
%
60 \%
60% 的数据,
n
≤
30
n \le 30
n≤30,
k
≤
30
k \le 30
k≤30,
m
≤
1000
m \le 1000
m≤1000。
对于
100
%
100 \%
100% 的数据,
0
≤
n
,
m
≤
1
0
6
0 \le n, m \le 10^6
0≤n,m≤106,
0
≤
k
≤
64
0 \le k \le 64
0≤k≤64,
1
≤
c
≤
1
0
8
1 \le c \le 10^8
1≤c≤108。
贪心
2z-n。
z= 0
如果拥有pj的动物,则需要购买他所需要的所有饲料。vector<vector> need(k);记录动物需要的饲料。unordered_set has;记录需要购买的饲料
枚举各位,如果此动物需要的饲料都在has中存在,z++。
1ull << 64 会溢出。 所以:
如果 已有动物为0,z= 64。新增的动物数量会超出 uint64。故直接用字符串表示。
如果已有动物不为0,z = 64,则:
return ULLONG_MAX - (unsigned long long)a.size() + 1ull;
** 注意**:
一,不同的动物可能需要相同的饲料。
二,一种动物可能需要多种饲料。
代码
核心代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include <bitset>
using namespace std;
template<class T = int>
vector<T> Read(int n,const char* pFormat = "%d") {
vector<T> ret;
T d ;
while (n--) {
scanf(pFormat, &d);
ret.emplace_back(d);
}
return ret;
}
template<class T = int>
vector<T> Read( const char* pFormat = "%d") {
int n;
scanf("%d", &n);
vector<T> ret;
T d;
while (n--) {
scanf(pFormat, &d);
ret.emplace_back(d);
}
return ret;
}
string ReadChar(int n) {
string str;
char ch;
while (n--) {
do
{
scanf("%c", &ch);
} while (('\n' == ch));
str += ch;
}
return str;
}
class Solution {
public:
unsigned long long MaxS(bool& bErr, const vector<unsigned long long>& a, const vector<pair<int, int>>& buy, int C, int k) {
bErr = false;
vector<bool> mask(k);//记录已有动物
for (const auto& i : a) {
for (int j = 0; j < k; j++) {
if ((1ULL << j) & i) { mask[j] = true; }
}
}
unordered_set<int> has;//记录需要购买的饲料
vector<vector<int>> need(k);//动物需要的饲料
for (const auto& [i, tmp] : buy) {
need[i].emplace_back(tmp);
if (mask[i]) { has.emplace(tmp); }
}
int z = 0;
for (int i = 0; i < k; i++) {
bool can = true;
for (const auto& j : need[i]) {
if (!has.count(j)) { can = false; }//缺少此动物需要的饲料
}
z += can;
}
if (64 == z) {
if (a.size() == 0) { bErr = true; }
return ULLONG_MAX - (unsigned long long)a.size() + 1ull;
}
return (1ULL << z) - (unsigned long long)a.size();
}
};
int main() {
#ifdef _DEBUG
freopen("a.in", "r", stdin);
#endif // DEBUG
int n,m,c,k;
scanf("%d%d%d%d", &n,&m,&c,&k);
auto a = Read<unsigned long long>(n,"%llu");
vector<pair<int, int>> buy;
for (int i = 0; i < m; i++) {
int i1, i2;
scanf("%d%d", &i1, &i2);
buy.emplace_back(i1, i2);
}
bool bErr;
auto res = Solution().MaxS(bErr,a,buy,c,k);
if (bErr) {
puts("18446744073709551616"); return 0;
}
cout << res << std::endl;
return 0;
}
单元测试
vector<unsigned long long> a;
vector<pair<int, int>> buy;
bool bErr;
TEST_METHOD(TestMethod11)
{
a = { 1 ,4 ,6 }, buy = { {0,3},{2,4},{2,5} };
auto res = Solution().MaxS(bErr,a, buy,5,4 );
AssertEx(13ULL, res);
}
TEST_METHOD(TestMethod12)
{
a = { 1 ,2 }, buy = { {1,3},{2,4} };
auto res = Solution().MaxS(bErr,a, buy,4, 3);
AssertEx(2ULL, res);
}
TEST_METHOD(TestMethod13)
{
a = { ULLONG_MAX }, buy = {};
auto res = Solution().MaxS(bErr,a, buy, 1,64);
AssertEx(ULLONG_MAX, res);
}
TEST_METHOD(TestMethod14)
{
a = { }, buy = {};
auto res = Solution().MaxS(bErr, a, buy,1, 64);
AssertEx(true, bErr);
}
TEST_METHOD(TestMethod15)
{
a = { }, buy = { {1,1} };
auto res = Solution().MaxS(bErr, a, buy,1, 64);
AssertEx(false, bErr);
}
TEST_METHOD(TestMethod16)
{
a = { 1 }, buy = { };
auto res = Solution().MaxS(bErr, a, buy,1, 64);
AssertEx(false, bErr);
}
TEST_METHOD(TestMethod17)
{
a = { 1 }, buy = { {0,1},{1,1} };
auto res = Solution().MaxS(bErr, a, buy, 1, 2);
AssertEx(3ull, res);
}
TEST_METHOD(TestMethod18)
{
a = { 1 }, buy = { {1,1},{0,1},{0,2} };
auto res = Solution().MaxS(bErr, a, buy, 2, 2);
AssertEx(3ull, res);
}
TEST_METHOD(TestMethod19)
{
a = { 2 }, buy = { {1,1},{0,1},{0,2} };
auto res = Solution().MaxS(bErr, a, buy, 2, 2);
AssertEx(1ull, res);
}
扩展阅读
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。