题解AcWing 1875 贝茜的报复
题目描述:
农夫约翰和奶牛贝茜喜欢在业余时间互相出数学题。
约翰给贝茜出了一道相当难的问题,导致她没能解决。
现在,她希望通过给约翰出一道有挑战性的难题来报复他。
贝茜给了约翰一个表达式 (B+E+S+S+I+E)(G+O+E+S)(M+O+O),其中包含七个变量 B,E,S,I,G,O,M(O 是变量,不是零)。
对于每个变量,她给约翰一个列表,表中包含该变量可采用的最多 20 个整数值。
她要求约翰计算,共有多少种给变量赋值的方法可以使得表达式的计算结果为偶数。
输入格式
第一行包含一个整数 N。
接下来 N 行,每行包含一个变量和该变量的一个可能值。
每个变量至少出现 1 次,最多出现 20 次。
同一变量不会重复列出同一可能值。
输出格式
输出可以使得表达式的计算结果是偶数的给变量赋值的方法总数。
数据范围
7≤N≤140,
所有变量的可能取值范围 [−300,300]
本题答案不会超出int范围。
输入样例:
10
B 2
E 5
S 7
I 10
O 16
M 19
B 3
G 1
I 9
M 2
输出样例:
6
题目分析:
因为题目已经给出了表达式,已知一个变量最多有20种取值,那么暴力来求解的话就有20^7 = 1280000000种情况,肯定超出了1s的时间限制,所以要考虑优化。
而这个题目只要求求出使结果是偶数的情况,偶数是做取模运算,取模运算常用性质:(a+b) mod c= (a mod c) + (b mod c),所以可以对每个变量先取模,就变成了2^7=128种情况,此时可以枚举。同时在枚举每一种情况时,由于有两个S和E,和一定为偶数,所以可以忽略。所以就只剩下遍历(B+I), (G+O+E+S), (M)共7种情况。如果三个因子里面有一个是偶数,那么答案就一定是偶数(奇数 * 奇数=奇数,偶数 * 偶数 = 偶数 , 奇 * 偶 = 偶)
#include<algorithm>
#include<iostream>
using namespace std;
int ans;
map<char, int> mp1, mp2, a; //mp1存每一个字母奇数的个数,a表示
string s = "BESIGOM";
void dfs(int u, int x)
{
if(u == 7)
{
if((a['B'] + a['I']) % 2
&& (a['G'] + a['O'] + a['E'] + a['S']) % 2
&& a['M'] % 2 ) return; //如果都是1表示都是奇数,此时肯定是奇数
//如果满足有一个是偶数,则算上这种情况
ans += x;
return;
}
char ch = s[u];
a[ch] = 1;
dfs(u+1, x * mp1[ch]); //遍历ch是奇数的情况
a[ch] = 2;
dfs(u+1, x * mp2[ch]); //遍历ch是偶数的情况
}
int main()
{
int n;
cin >> n;
for(int i=0; i<n; i++)
{
char c;
int x;
cin >> c >> x;
if(x%2 == 1) mp1[c]++; //c字母为奇数的情况加一
else mp2[c]++;
}
dfs(0, 1); //从第一层开始遍历
cout << ans;
return 0;
}
//代码是嫖大佬的题解来的:https://www.acwing.com/solution/content/86729/