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

样例解释

共有 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

思路

可以将公式简化为(B+I)*(G+O+E+S)*(M),判断这个式子的奇偶性。

搜先可以想到暴力求解,也就是枚举每个字母的取值情况,这样每个字母最多可以取20个数,

7个字母的话时间复杂度就是O(20^7),TLE是肯定的。

这里有一个简化就是,判断这7个字母是奇数还是偶数,这样每个字母的取值不是偶数就是奇数,就只有有两种情况。

遍历所有情况可以分为两个流派:

DFS流派:优点是时间复杂度低O(2^n),缺点是代码长。

二进制流派:优点是代码短,缺点是时间复杂度较高O(n*n^n)。

对于这个题,不论是什么流派,做题步骤就是:

记录每一个字母的奇数,偶数的个数

枚举每一个字母的奇数和偶数的情况(2^7种情况)

满足 B + I,或者 G + O + E + S 或者 M 其中一个为偶数,则答案为偶数

假如满足,累加到答案res中

一、DFS

#include<bits/stdc++.h>
using namespace std;

int n;
unordered_map<char,int>cnt[2];
char str[]="BESIGOM";
int res=0;
unordered_map<char,int>v;

void dfs(int u,int x) {
    if(u==7) {
        if ((v['B'] + v['I']) * (v['G'] + v['O'] + v['E'] + v['S']) * v['M'] % 2 == 0) {
            res+=x;
        }
        return;
    }

    char c=str[u];
//    cout<<x*cnt[1][c]<<endl;
    v[c]=1,dfs(u+1,x*cnt[1][c]);//枚举c为奇数的情况,累乘答案
    v[c]=0,dfs(u+1,x*cnt[0][c]);//枚举c为偶数的情况,累乘答案
}


int main() {

    cin>>n;
    while(n--) {
        char c;
        int x;
        cin>>c>>x;
        cnt[abs(x)%2][c]++;
    }
    //开始枚举每个字符的奇偶情况
    dfs(0,1);//当前枚举到那个字母了,当前的取值情况的方案数
    cout<<res;
    return 0;
}

二、二进制

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+10;

signed main() {
    int n;

    cin>>n;
    unordered_map<char,int>cnt[2];

    while(n--) {
        char c;
        int x;
        cin>>c>>x;
        cnt[abs(x)%2][c]++;
    }

    char str[]="BESIGOM";

    int res=0;

    unordered_map<char,int>v;

    //开始枚举每个字符的奇偶情况
    for(int i=0; i<1<<7; i++) {
        for(int j=0; j<7; j++) {
            v[str[j]]=i>>j&1;
        }

        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[i>>j&1][str[j]];
            }
            res+=sum;
        }
    }
    cout<<res;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值