目录:算法日记
题目描述
农夫约翰和奶牛贝茜喜欢在业余时间互相出数学题。
约翰给贝茜出了一道相当难的问题,导致她没能解决。
现在,她希望通过给约翰出一道有挑战性的难题来报复他。
贝茜给了约翰一个表达式 ,其中包含七个变量 。
对于每个变量,她给约翰一个列表,表中包含该变量可采用的最多 个整数值。
她要求约翰计算,共有多少种给变量赋值的方法可以使得表达式的计算结果为偶数。
输入格式
第一行包含一个整数 。
接下来 行,每行包含一个变量和该变量的一个可能值。
每个变量至少出现 次,最多出现 次。
同一变量不会重复列出同一可能值。
输出格式
输出可以使得表达式的计算结果是偶数的给变量赋值的方法总数。
数据范围
- 所有变量的可能取值范围
- 本题答案不会超出
int
范围。
算法思路
题目要求计算共有多少种给变量赋值的方法可以使得表达式的计算结果为偶数,先考虑暴力计算每种可能是否可解。题目中共给出了个变量,每个变量最多可以采用个整数的值,因此所有的可能的情况共有种。考虑优化。
注意仅统计为偶数的计算结果,求偶数等价于除以的余数等于。对于乘法、加法和减法,取余运算有分配律,即每个变量的值直接对取余,仅存在两种情况,对应所有可能的情况减少到种,这样处理之后可以暴力求解。
个变量使用位二进制位数表示,枚举每种结果为偶数的组合,根据乘法原理,计算合法赋值方式的组合。由于相同的两个数相加一定是偶数,可利用这个性质简化判断条件。
AC代码
#include<iostream>
#include<map>
using namespace std;
map<char, int> cnt[2];
int n;
int main() {
cin>>n;
for(int i = 0; i < n; ++i) {
char c;
int x;
cin>>c>>x;
cnt[abs(x % 2)][c]++;
}
char str[] = "BESIGOM";
int res = 0;
//枚举每种可能
for(int i = 0; i < 1 << 7; ++i) {
map<char, int> v;
// 取出每一位
for(int j = 0; j < 7; ++j) {
v[str[j]] = i >> j & 1;
}
// 判断合法方案数量,if成立说明当前枚举到的状态合法
if((v['B'] + v['I']) * (v['G'] + v['O'] + v['E'] + v['S']) * v['M'] % 2 == 0) {
int sum = 1;
for(int j = 0; j < 7; ++j) {
sum *= cnt[v[str[j]]][str[j]];
}
res += sum;
}
}
cout<<res<<endl;
return 0;
}
复制代码