【数学思维】数学难题

调节字体颜色和大小

开头小喷:哈哈哈,我也会用彩色字体啦,夸夸我自个儿,真棒,嘻嘻嘻
来换个颜色。来啦,五月的第一篇博客,新的月份,新的开始,加油,小明同学。嘿嘿,好啦到此结束。
、、、、、、
下面切入正题

题目:Contest2380 - 2020年春混合个人训练第五场 E: 数学难题
题目描述
学佛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,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
【数据规模】
对于30%的数据,N<=60。
对于100%的数据,N<=140。

这道题一看规模不是很大,不过,不是很大的时候也要慎重考虑一下复杂度,千万别学我,一开始直接不动脑子就枚举七个for循环,小算一下,复杂度达到了27 * 1e7,差不多O(1e9)的复杂度了都,不超时都得说点啥了,以下我也会将我的没头脑写法放以下,以作警示:做题之间先算复杂度;赛后与小伙伴商讨之时瞬间相通;
首先对原式小做一番出理,对于那些在一个因式里出现两次的变量可直接去掉,因为偶数不影响最后结果是不是偶数的情况,所以 (B+E+S+S+I+E)(G+O+E+S)(M+O+O) 这个小东西就可以化为 (E+S+G+O)(B+I)M看起来是不是少了很多,嗯,确实变短了,但依照我一开始的那个思路,也还是会超时,因为变量并未减少;因此,就要考虑一番了,可想一下 两个值相乘只要一个值为偶数,那么结果必定为偶数,只有两个值都为奇数的时候,最后结果才是奇数,所以就衍生出了正解的思路:先计算出所有的组合情况ans1(所有变量的 值个数 相乘),然后再算出三个项的值都为奇数的情况ans2,也就是结果为奇数的情况,然后答案就是ans1-ans2啦
啰里啰嗦的说了半天,首先感谢你能坚持看到这儿,hh,也许之直接看代码会更好理解一点,其实思路也不是很难。

先放上正解代码:

#include<bits/stdc++.h>
using namespace std;
int B[22],E[22],S[22],I[22],G[22],O[22],M[22];
int main()
{
	int n,b=0,e=0,s=0,i=0,g=0,o=0,m=0;
	cin>>n;
	while(n--)
	{
		char type;
		int x;
		cin>>type>>x;
		if(type=='B')
		{
			B[++b]=x;
		}
		else if(type=='E')
		{
			E[++e]=x;
		}
		else if(type=='S')
		{
			S[++s]=x;
		}
		else if(type=='I')
		{
			I[++i]=x;
		}
		else if(type=='G')
		{
			G[++g]=x;
		}
		else if(type=='O')
		{
			O[++o]=x;
		}
		else if(type=='M')
		{
			M[++m]=x;
		}
	}
	int tmp1=0,tmp2=0,tmp3=0;
	int ans=b*e*s*i*g*o*m;
	for(int t2=1;t2<=e;t2++)
	{
		for(int t3=1;t3<=s;t3++)
		{
			for(int t5=1;t5<=g;t5++)
			{
				for(int t6=1;t6<=o;t6++)
				{
					if((E[t2]+S[t3]+G[t5]+O[t6])%2!=0) tmp1++;
				}
			}
		} 
	}
	for(int t1=1;t1<=b;t1++)
	{
		for(int t4=1;t4<=i;t4++)
		{
			if((B[t1]+I[t4])%2!=0) tmp2++;
		}
	}
	for(int t7=1;t7<=m;t7++) if(M[t7]%2!=0) tmp3++;
	
	cout<<ans-tmp1*tmp2*tmp3<<endl;
	return 0;
}
/*
	(E+S+G+O)*(B+I)*M;
*/

其中的那些变量t1 ,t2…纯属是为了和先后顺序对应而作

超时的无脑代码:

#include<bits/stdc++.h>
using namespace std;
int B[22],E[22],S[22],I[22],G[22],O[22],M[22];
int main()
{
    int n,b=0,e=0,s=0,i=0,g=0,o=0,m=0;
    cin>>n;
    while(n--)
    {
        char type;
        int x;
        cin>>type>>x;
        if(type=='B')
        {
            B[++b]=x;
        }
        else if(type=='E')
        {
            E[++e]=x;
        }
        else if(type=='S')
        {
            S[++s]=x;
        }
        else if(type=='I')
        {
            I[++i]=x;
        }
        else if(type=='G')
        {
            G[++g]=x;
        }
        else if(type=='O')
        {
            O[++o]=x;
        }
        else if(type=='M')
        {
            M[++m]=x;
        }
    }
    int ans=0;
    for(int t1=1;t1<=b;t1++)
    {
        for(int t2=1;t2<=e;t2++)
        {
            for(int t3=1;t3<=s;t3++)
            {
                for(int t4=1;t4<=i;t4++)
                {
                    for(int t5=1;t5<=g;t5++)
                    {
                        for(int t6=1;t6<=o;t6++)
                        {
                            for(int t7=1;t7<=m;t7++)
                            {
                                if((((B[t1]+E[t2]+S[t3]+S[t3]+I[t4]+E[t2])%2)*((G[t5]+O[t6]+E[t2]+S[t3])%2)*((M[t7]+O[t6]+O[t6])%2))%2==0) ans++;
                            }
                        }
                    }
                }
            }
        }   
    }
    cout<<ans<<endl;
    return 0;
}

比较简短的二进制枚举的写法

AcWing 1875 贝茜的报复

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n; cin >> n;
    unordered_map<char,int> cnt[2];
    string str = "BESIGOM";
    while(n--){
        char c;
        int x;
        cin >> c >> x;
        cnt[abs(x)%2][c]++;
    }
    unordered_map<char,int> v;
    int res = 0;
    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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值