【题目描述】
农夫约翰和奶牛贝茜喜欢在业余时间互相出数学题。
约翰给贝茜出了一道相当难的问题,导致她没能解决。
现在,她希望通过给约翰出一道有挑战性的难题来报复他。
贝茜给了约翰一个表达式
(
B
+
E
+
S
+
S
+
I
+
E
)
(
G
+
O
+
E
+
S
)
(
M
+
O
+
O
)
(B+E+S+S+I+E)(G+O+E+S)(M+O+O)
(B+E+S+S+I+E)(G+O+E+S)(M+O+O),其中包含七个变量
B
,
E
,
S
,
I
,
G
,
O
,
M
B,E,S,I,G,O,M
B,E,S,I,G,O,M(
O
O
O是变量,不是零)。
对于每个变量,她给约翰一个列表,表中包含该变量可采用的最多
20
20
20个整数值。
她要求约翰计算,共有多少种给变量赋值的方法可以使得表达式的计算结果为偶数。
【输入格式】
第一行包含一个整数
N
N
N。
接下来
N
N
N行,每行包含一个变量和该变量的一个可能值。
每个变量至少出现
1
1
1次,最多出现
20
20
20次。
同一变量不会重复列出同一可能值。
【输出格式】
输出可以使得表达式的计算结果是偶数的给变量赋值的方法总数。
【数据范围】
7
≤
N
≤
140
7≤N≤140
7≤N≤140
所有变量的可能取值范围
[
−
300
,
300
]
[−300,300]
[−300,300]
本题答案不会超出
i
n
t
int
int范围。
【输入样例】
10
B 2
E 5
S 7
I 10
O 16
M 19
B 3
G 1
I 9
M 2
【输出样例】
6
【样例解释】
共有
6
6
6种可能的赋值方式:
(B,E,S,I,G,O,M) = (2, 5, 7, 10, 1, 16, 19) -> 53,244
= (2, 5, 7, 10, 1, 16, 2 ) -> 35,496
= (2, 5, 7, 9, 1, 16, 2 ) -> 34,510
= (3, 5, 7, 10, 1, 16, 2 ) -> 36,482
= (3, 5, 7, 9, 1, 16, 19) -> 53,244
= (3, 5, 7, 9, 1, 16, 2 ) -> 35,496
注意,(2, 5, 7, 10, 1, 16, 19)
和(3, 5, 7, 9, 1, 16, 19)
,虽然计算结果相同,但是赋值方式不同,所以要分别计数。
【分析】
我们只需要判断式子最后的结果是否为偶数,因此可以将每个变量的不同取值分为两大类:奇数与偶数。分别统计每个变量取奇数的不同取值以及取偶数的不同取值的数量,然后使用一个 7 7 7位的二进制数的每一位分别表示 7 7 7种变量的取值状态,某一位为 0 0 0表示该变量取偶数,为 1 1 1表示取奇数,对于每一种状态,如果在该状态下式子的运算结果为偶数,则将每个变量在该奇偶状态下的取值的数量相乘,即为该状态下的计数结果,最后将每种状态的计数结果累加即为最终结果。
【代码】
#include <iostream>
#include <unordered_map>
using namespace std;
int n, res;
unordered_map<char, int> cnt[2];//cnt[0][c]表示字符c为偶数的次数,1表示为奇数的次数
char s[] = "BESIGOM";
int main()
{
cin >> n;
while (n--)
{
char c; int x;
cin >> c >> x;
cnt[abs(x) % 2][c]++;
}
unordered_map<char, int> v;//v[c]表示字符c为奇数还是偶数
for (int i = 0; i < 1 << 7; i++)//枚举所有奇偶组合状态
{
for (int j = 0; j < 7; j++) v[s[j]] = i >> j & 1;
if ((v['B'] + v['I']) * (v['G'] + v['O'] + v['E'] + v['S']) * v['M'] % 2 == 0)
{
int t = 1;
for (int j = 0; j < 7; j++) t *= cnt[v[s[j]]][s[j]];
res += t;
}
}
cout << res << endl;
return 0;
}