一题解:
阅读前必备知识点:奇数加减奇数为偶数,偶数加减偶数为偶数,奇数加减偶数为奇数
由题意可知S1+S2=sum(sum是整个A数组的和),且知道S1和S2是偶数,根据数学性质偶数相加减偶数还是得到偶数
可知sum为奇数必定无解结果为0,所以sum必须为偶数。
接下来根据上面的推导也不难得出一个结论:当sum为偶数,S1为偶数,S2一定为偶数。
所以在sum为偶数的情况下我们只需要确保S1是偶数即可。
根据阅读前必备知识点得出:1.A数组里任意的偶数子集相加必定也为偶数,2。偶数个奇数相加为偶数,所以从A数组中的奇数子集中任选偶数个,就能保证选出的奇数子集相加也为偶数.,由1和2得出:只需要从A数组任意偶数子集中选和A数组中奇数子集中任选偶数个组合在一起就能枚举所有符合S1是偶数的情况。
接下来让我们推导公式计算有多少符合条件的情况:首先设so为A的偶数集合,sj为A的奇数集合,so的长度为r,sj的长度为l,首先我们从so中任取一个集合,so里面每个数可选和不选,利用分布积分法计算可得。
接下来推导sj有多少个子集:首先给出结论,l必须为偶数,为了确保s1和s2为偶数,和S1必须只能包含偶数个的奇数,S2也必须包含偶数个的奇数,所以l=R1里的奇数个数+R2里的奇数个数,偶数加减偶数任然为偶数,则l为偶数。
由于推导过于困难,并且考虑在考场时间紧迫,不如按照规律大胆推测
我们可以根据规律得出:sj的集合数=2^l-1
最终S1的选择方法数=(2^r)*(2^(r-1))(分布积分法)
二,代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <unordered_map>
#include <string>
using namespace std;
using ll = long long;
const ll mod = 1000000007;
ll f(ll a, ll n) //快速幂
{
if (n < 0) return 1;
ll res = 1;
while (n)
{
if (n%2!=0) res = res * a % mod;
a = a * a % mod;
n >>= 1;
}
return res % mod;
}
int main() {
ll t;
cin >> t;
while (t--)
{
ll n;
cin >> n;
ll r = 0, l = 0;//r=偶数个数,l=奇数个数
ll sum = 0;
for (int i = 1; i <= n; i++)
{
ll temp;
cin >> temp;
sum += temp;
if (temp % 2 == 0)r++;
else l++;
}
if (sum % 2 != 0)
{
cout << 0 << endl;
}
else
{
cout << f(2, r) % mod * f(2, l - 1) % mod << endl;
}
}
}