upc 数学难题(枚举+容斥)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

学佛Fife最喜欢Bemy上的数学课了。因为他可以在数学课上尽情的蒸发学水~

Bemy为了不让学佛Fife过度骄傲,以保证每一个学水都能不被他影响,自信地不断地进步,给Fife一个有挑战性的数学题。

因为Fife不想让妹子Maze等得太久,决定把这道题交给你。

题目是这样的:有一个表达式(B+E+S+S+I+E)(G+O+E+S)(M+O+O)

其中B,E,S,I,G,O,M为七个变量(注意“O”是变量不是0)。

对于每个变量,Bemy会告诉Fife这个变量所代表的各个可能值。

Bemy想问问Fife这样一个问题:原表达式有多少种可能的情况,使表达式的值为偶数。(只要有一个变量的值不同,即为一种情况)

输入

第一行输入包含一个整数N。

下一个N 行每行包含一个变量名称和一个这个变量可以使用的值。

注:每个变量在整张表中不会出现多于20 次。

同一个变量不存在两个相同的值。所有给出的值都在-300……300 之间。

输出

打印出一个整数,表示有多少种方法使表达式的值为一个偶数。

样例输入
10
B 2
E 5
S 7
I 10
O 16
M 19
B 3
G 1
I 9
M 2
样例输出
6
思路:

题目要求表达式值为偶数,其实我们只要保证有一个括号内的和是偶数,就能确定整个表达式的值是偶数。

先看第一个括号内的数,B+I+S+S+E+E,因为偶数 + 偶数 = 偶数,又因为S+S+E+E 是偶数,所以我们只要确定 B + I 是不是偶数,就可以判断这个括号内的数字之和是不是偶数,也就是说这个括号和的奇偶是由 B + I 决定的,同理,第二个括号由 G + O + E + S 决定,第三个括号由 M 决定。

接下来我们把第一个括号的和为偶数的情况设为 A 类;
第二个括号的和为偶数的情况设为 B 类;
第三个括号的和为偶数的情况设为 C 类;

根据容斥原理得:

(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)

( 文字翻译为A类和B类和C类元素个数总和= A类元素个数+ B类元素个数+C类元素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类又是C类的元素个数+既是A类又是B类而且是C类的元素个数。)

此式结果就是我们想要的答案

下面是代码:

#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=2e5+10;
char s[7]={'B','I','S','E','G','O','M'};
vector<int>v[200];
int n,m,fa,fb,fc,oa,ob,oc;//后 6个变量分别代表第一、二、三个括号内所有的方案数
char ch;                  //与第一、二、三括号内数字和为偶数的方案数
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>ch>>m;
        v[ch].push_back(m);
    }
    fa=v[s[0]].size()*v[s[1]].size();
    fb=v[s[2]].size()*v[s[3]].size()*v[s[4]].size()*v[s[5]].size();
    fc=v[s[6]].size();
    for(int i=0;i<v[s[0]].size();i++)
    {
        for(int j=0;j<v[s[1]].size();j++)
        {
            if((v[s[0]][i]+v[s[1]][j])%2==0) oa++;
        }
    }
    for(int i=0;i<v[s[2]].size();i++)
    {
        for(int j=0;j<v[s[3]].size();j++)
        {
            for(int k=0;k<v[s[4]].size();k++)
            {
                for(int z=0;z<v[s[5]].size();z++)
                {
                    if((v[s[2]][i]+v[s[3]][j]+v[s[4]][k]+v[s[5]][z])%2==0) ob++;
                }
            }
        }
    }
    for(int i=0;i<v[s[6]].size();i++)
    {
        if(v[s[6]][i]%2==0) oc++;
    }
    ll ans=oa*fb*fc+ob*fa*fc+oc*fa*fb-oa*ob*fc-oa*oc*fb-ob*oc*fa+oa*ob*oc;
    //(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值