开头小喷:哈哈哈,我也会用彩色字体啦,夸夸我自个儿,真棒,嘻嘻嘻
来换个颜色。来啦,五月的第一篇博客,新的月份,新的开始,加油,小明同学。嘿嘿,好啦到此结束。
、、、、、、
下面切入正题
题目: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;
}
比较简短的二进制枚举的写法
#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;
}