CSP-S 2020 T2动物园
用第二个样例对题目进行分析:
2 2 4 3
1 2
1 3
2 4
动物世界中共有
2
3
=
8
2^3=8
23=8种动物,编号为
0
∼
7
0\sim7
0∼7。动物园饲养了其中的
2
2
2种,编号为
1
1
1和
2
2
2。
根据饲养指南,第
1
1
1位为
1
1
1的动物需要编号为
3
3
3的饲料,第
2
2
2位为
1
1
1的动物需要编号为
4
4
4的饲料。
我们分别看动物园饲养的
2
2
2种动物各需要什么饲料:
- 编号为 1 1 1的动物,其二进制为 001 001 001,其第 0 0 0位为 1 1 1,不需要饲料;
- 编号为 2 2 2的动物,其二进制为 010 010 010,其第 1 1 1位为 1 1 1,需要编号为3的饲料;
所以饲养这两种动物只需要编号为
3
3
3的饲料。
总共有
8
8
8种动物,它们的二进制分别是:
动物编号 | 第2位 | 第1位 | 第0位 |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 |
2 | 0 | 1 | 0 |
3 | 0 | 1 | 1 |
4 | 1 | 0 | 0 |
5 | 1 | 0 | 1 |
6 | 1 | 1 | 0 |
7 | 1 | 1 | 1 |
只用编号为 3 3 3的饲料可以饲养 4 4 4种动物,分别是 0 0 0号动物、 1 1 1号动物、 2 2 2号动物、 3 3 3号动物,因为第 0 0 0位为 1 1 1不需要饲料、第 1 1 1位为 1 1 1需要编号为 3 3 3的饲料。而现在已经饲养了 1 1 1号动物和 2 2 2号动物,所以还能饲养 0 0 0号动物和 3 3 3号动物,共 2 2 2个动物,答案为 2 2 2。
设可以为
1
1
1的位数为
x
x
x,则最后的答案为
2
x
−
n
2^x-n
2x−n。对于上面的样例,
x
x
x为
2
2
2,分别是第
0
0
0位和第
1
1
1位。
对于每一个输入进来的动物编号
a
i
a_i
ai,我们记录它是否使第
i
i
i位为
1
1
1。
每当输入一个位数
p
i
p_i
pi后,如果存在某个动物的编号使这一位为
1
1
1,那么这一位就不能为
1
1
1了。累计不能为
1
1
1的位的数量
s
u
m
sum
sum,
k
−
s
u
m
k-sum
k−sum就是可以为
1
1
1的位的数量,相当于上面的
x
x
x(
k
−
s
u
m
=
x
k-sum=x
k−sum=x)。
有一个比较特殊的数据点是
n
=
0
,
m
=
0
,
k
=
64
n=0,m=0,k=64
n=0,m=0,k=64,此时答案会爆
l
o
n
g
l
o
n
g
long\ long
long long,
2
64
2^{64}
264比unsigned long long
还要大
1
1
1,所以最好是直接特判输出。
#include <bits/stdc++.h>
#define A 66
using namespace std;
typedef long long ll;
ll a;
int cnt, p, q, sum, k, c, m, n;
bool used[A], nd[A];
int main(int argc, char const *argv[]) {
scanf("%d%d%d%d", &n, &m, &c, &k);
if (n == 0 and m == 0 and k == 64) {
cout << "18446744073709551616\n";
return 0;
}
for (int i = 1; i <= n; i++) {
scanf("%lld", &a);
cnt = 0;
while (a) {
if (a % 2) nd[cnt] = 1;
cnt++;
a /= 2;
}
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &p, &q);
if (!nd[p] and !used[p]) {
sum++;
used[p] = 1;
}
}
ll ans = 1;
for (int i = 1; i <= k - sum; i++) ans *= 2;
printf("%lld\n", ans - n);
}