贝茜的报复

本文介绍了一个涉及奇偶性计算的编程挑战,农夫约翰和奶牛贝茜之间的数学游戏。挑战要求计算给定变量的不同赋值组合,使表达式结果为偶数的总数。解决方案包括利用变量取值对2求余的统计,通过二进制枚举或深度优先搜索策略,结合数学性质判断结果的奇偶性。
摘要由CSDN通过智能技术生成

目录

1.题目描述

2.题意分析

3.解题思路

4.代码实现,

5.附录


1.题目描述

农夫约翰和奶牛贝茜喜欢在业余时间互相出数学题。

约翰给贝茜出了一道相当难的问题,导致她没能解决。

现在,她希望通过给约翰出一道有挑战性的难题来报复他。

贝茜给了约翰一个表达式 (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

样例解释

共有 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),虽然计算结果相同,但是赋值方式不同,所以要分别计数。

2.题意分析

题意:对输入的七个变量B,E,S,I,G,O,M的各种取值,进行组合,并代入题目给出的式子(B+E+S+S+I+E)(G+O+E+S)(M+O+O),若式子的结果为偶数,则符合要求,最终要求输出符合要求的赋值方式的个数

3.解题思路

思路1:因为式子的结果为奇数还是偶数,可以看作是对式子整体进行求余,若结果为0则式子的结果偶数,若为1则为奇数。根据性质1(详见附录),则可先将输入的各个变量的取值求余2的结果统计起来。然后采用二进制枚举的方法,确定7个变量的取值是1还是0,然后再将这七个变量的取值带入式子中去,若式子符合要求,则再计算一下该种取值的个数有多少种,并累加到最终结果中

思路2:因为式子的结果为奇数还是偶数,可以看作是对式子整体进行求余,若结果为0则式子的结果偶数,若为1则为奇数。根据性质1(详见附录),则可先将输入的各个变量的取值求余2的结果统计起来。然后再采用DFS的方法,每一步的状态为确定当前变量的取值,状态的选择有0和1可选,问题边界为式子的答案确认与否。通过这种方法逐步确定7个变量得取值是1还是0,根据性质1和2,我们可以在判断出部分乘数((MorG+O+E+SorB+I),式子化简过程详见附录末尾)为偶数后,确定含该种变量的取值都符合条件,则可直接计算该种类型的取值的个数有多少种,并累加到最终结果中。

4.代码实现,

思路1代码:

a[26][2]:存储输入的各个变量取值求余2后的两种取值0或者1的个数

d[7]:设定的7个变量的顺序

oor[10]:存储当前枚举次序的各个变量的取值

代码思路:因为题目中,输入的取值有可能是负数,所以先将输入的取值求绝对值,然后求余2,再存入对应的a[][]中。因为有7个变量需要确定,所以由0,枚举到(2^{7}-1)即(1<<7-1)。然后通过(i>>j&1)的方式,将每次枚举的第j个变量的取值取出来,若a[d[j]-'A'][]==0,则代表第j个变量,并未有这种类型的取值,则break,否则将该种取值存入oor[j]中。当7个变量确定后,带入化简后的式子(化简过程详见附录末尾),若满足条件,则计算一下,该种类型的取值有多少种,累加到ans上。枚举完后输出ans。

#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;

int a[26][2];
int n, ans = 0;
int oor[10];
char d[7] = { 'M','O','S','E','G','I','B' };

void check() {

	int sum = (oor[6]+oor[5])*(oor[4]+oor[3]+oor[2]+oor[1])*oor[0];
	if(sum%2==0){
		sum=1;
		for(int i=0;i<7;i++){
		    sum*=a[d[i]-'A'][oor[i]];
		}
		ans+=sum;
	}
}


int main() {
	cin >> n;
	for (int i = 0; i < n; i++) {
	    char c;
	    int za;
		cin >>c >>za;
		a[c - 'A'][abs(za)%2]++;
	}
    for(int i=0;i<(1<<7);i++){
        for(int j=0;j<7;j++){
           if(i>>j&1){
               if(a[d[j]-'A'][1]==0)   break;
               oor[j]=1;
           }
           else {
               if(a[d[j]-'A'][0]==0)    break;
               oor[j]=0;
           }
           if(j==6) check();
        }
    }
	cout << ans << endl;
	return 0;
}

思路2代码:

a[26][2]:存储输入的各个变量取值求余2后的两种取值0或者1的个数

st[26][2]:判断各个变量的该种取值是否使用

d[7] = { 'M','O','S','E','G','I','B' }:设定的7个变量的顺序,按部分来分,则有M,OSEG,BI,三个部分

oor[10]:存储当前枚举次序的各个变量的取值

代码思路:先对st和oor数组进行初始化,所以先将输入的取值求绝对值,然后求余2,再存入对应的a[][]中。然后开始dfs,因为初始时没有变量确定,故dfs(0)。在dfs()中,枚举变量t取0和1的两种情况,当该种情况没有被选时让oor[t]=0,或oor[t]=1,然后将该种情况标记一下,然后dfs(t+1)。当t==1,或t==5,t==7时,因为此时已经确定了式子的一部分,可以通过check()代入式子的一部分,来判断整个式子的奇偶,若符合条件,则计算一下,该种情况的个数然后累加到ans上,若不满足则继续枚举,或返回并恢复状态。

#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;

int a[26][2];
bool st[26][2];
char d[7] = { 'M','O','S','E','G','I','B' };
int n, ans = 0;
int oor[10];

bool check(int t) {

	if (t == 7) {
		int sum = (oor[6] + oor[5]);
		if (sum % 2 == 0) {
			sum = 1;
			for (int i = 0; i < 7; i++) {
				sum *= a[d[i] - 'A'][oor[i]];
			}
			ans += sum;
			return true;
		}
	}
	if (t == 5) {
		int sum = (oor[4] + oor[3] + oor[2] + oor[1]);
		if (sum % 2 == 0) {
			sum = 1;
			for (int i = 0; i < 5; i++) {
				sum *= a[d[i] - 'A'][oor[i]];
			}
			for (int i = 5; i < 7; i++) {
				sum *= (a[d[i] - 'A'][0] + a[d[i] - 'A'][1]);
			}
			ans += sum;
			return true;
		}
	}
	if (t == 1) {
		int sum = (oor[0]);
		if (sum % 2 == 0) {
			sum = 1;
			for (int i = 0; i < 1; i++) {
				sum *= a[d[i] - 'A'][oor[i]];
			}
			for (int i = 1; i < 7; i++) {
				sum *= (a[d[i] - 'A'][0] + a[d[i] - 'A'][1]);
			}
			ans += sum;
			return true;
		}
	}

	return false;
}


void dfs(int t) {
	if ((t == 1 || t == 5 || t == 7) && check(t)) {
		return;
	}

	int now = d[t] - 'A';
	for (int j = 0; j < 2; j++) {
		if (!st[now][j]) {
			oor[t] = j;
			st[now][j] = true;
			dfs(t + 1);
			st[now][j] = false;
			oor[t] = -1;
		}
	}
}

int main() {
	cin >> n;
	memset(st, false, sizeof st);
	memset(oor, -1, sizeof oor);
	for (int i = 0; i < n; i++) {
		char c;
		int za;
		cin >> c >> za;
		a[c - 'A'][abs(za) % 2]++;
	}
	dfs(0);
	cout << ans << endl;
	return 0;
}

5.附录

性质1:各个变量先运算再求余2等价于,先对各个变量求余2再运算

性质2:乘法运算中含偶数参与,则结果为偶数

证明1:乘法:(a*b)%2=a%2*b%2。乘法运算中含偶数参与,则结果为偶数

a*b有三种情况

1.奇数*偶数

2.奇数*奇数

3.偶数*偶数

1.奇数*偶数

先运算再求余2

(2n+1)*2m=2(m*n+m),求余2得0。

先求余2再运算

1*0=0,故情况1符合预期

2.奇数*奇数

先运算再求余2

(2n+1)*(2m+1)=2(m*n+n+m)+1,求余2得1。

先求余2再运算

1*1=1,故情况2符合预期

3.偶数*偶数

先运算再求余2

(2n)*(2m)=2(n*m),求余2得0。

先求余2再运算

0*0=0,故情况3符合预期

证明1成立,性质2成立

证明2:加法:(a+b)%2=a%2+b%2。

1.奇数+偶数

2.奇数+奇数

3.偶数+偶数

1.奇数+偶数

先运算再求余2

(2n+1)+2m=2(n+m)+1,求余2得1。

先求余2再运算

1+0=1,故情况1符合预期

2.奇数+奇数

先运算再求余2

(2n+1)+(2m+1)=2(n+m+1),求余2得0。

先求余2再运算

1+1=0,故情况2符合预期

3.偶数+偶数

先运算再求余2

(2n)+(2m)=2(n+m),求余2得0。

先求余2再运算

0+0=0,故情况3符合预期

证明2成立

式子化简:

根据性质1,式子中只有乘法和加法运算,这两种运算经证明,都可以先求余2再运算,故该式子可以先进行求余2,再运算。

则有,

 (B+E+S+S+I+E)*(G+O+E+S)*(M+O+O)%2

=(B+I+S*2+E*2)*(G+O+E+S)*(M+2*O)%2

=(B%2+I%2)*(G%2+O%2+E%2+S%2)*M%2

整个式子,由三个部分(B%2+I%2)*(G%2+O%2+E%2+S%2)*M%2相乘而得,根据性质2,只要这三个部分有一个为偶数,则整个式子的结果也为偶数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值