题目描述
小蓝有一个长度为 N 的数组 A = [A0, A1,…, AN−1]。现在小蓝想要从 A 对应的数组下标所构成的集合 I = {0, 1, 2, . . . , N − 1} 中找出一个子集 R1,那么 R1在 I 中的补集为 R2。记 S1=∑r∈R1Ar,S2 =∑r∈R2Ar,我们要求 S1 和 S2 均为偶数,请问在这种情况下共有多少种不同的 R1。当 R1 或 R2 为空集时我们将 S1 或 S2 视为 0。
输入格式
第一行一个整数 T,表示有 T 组数据。
接下来输入 T 组数据,每组数据包含两行:第一行一个整数 N,表示数组 A 的长度;第二行输入 N 个整数从左至右依次为 A0, A1, . . . , AN−1,相邻元素之间用空格分隔。
输出格式
对于每组数据,输出一行,包含一个整数表示答案,答案可能会很大,你需要将答案对1000000007 进行取模后输出。
样例输入
2
2
6 6
2
1 6
样例输出
4
0
提示
对于第一组数据,答案为 4。(注意:大括号内的数字表示元素在数组中的下标。)
R1 = {0}, R2 = {1};此时 S1 = A0 = 6 为偶数, S2 = A1 = 6 为偶数。
R1 = {1}, R2 = {0};此时 S1 = A1 = 6 为偶数, S2 = A0 = 6 为偶数。
R1 = {0, 1}, R2 = {};此时 S1 = A0 + A1 = 12 为偶数, S2 = 0 为偶数。
R1 = {}, R2 = {0, 1};此时 S1 = 0 为偶数, S2 = A0 + A1 = 12 为偶数。
对于第二组数据,无论怎么选择,都不满足条件,所以答案为 0。
对于 20% 的评测用例,1 ≤ N ≤ 10。
对于 40% 的评测用例,1 ≤ N ≤ 102。
对于 100% 的评测用例,1 ≤ T ≤ 10, 1 ≤ N ≤ 103 , 0 ≤ Ai ≤ 109。
思路分析
-
直接遍历数组,统计奇偶的个数
0为偶数
-
R1的种树:
-
当奇数的个数为奇数个时,不符合题意
-
当奇数的个数为偶数个是,和为偶数,满足题意
-
此时种数为 2 n 2^n 2n* 2 i 2^i 2i (n为偶数个数,i为奇数个数)
-
2的n次方有选和不选两种情况
-
i,如果大于0就减1,否则不变
- 0不变,此时没有奇数,只有一种可能 2 0 2^0 20=1
- 减1,奇数只能成对凑,要去掉一半的情况
假设有数组 [1,1,2]
R1 R2 1,1 2 2 1,1 2,1,1 空集 空集 2,1,1 偶数可以单独出现,奇数必须成对出现
-
-
代码
public class ArraySpilt {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int T = scanner.nextInt(); //有T组数据
int[] res = new int[T]; //存放每组数据最终R1的可能性
for (int i = 0; i < T; i++) {
int len = scanner.nextInt(); //数组的长度
int evenCount = 0 , oddCount = 0; //初始化偶数个数和奇数个数
for (int j = 0; j < len; j++) {
int data = scanner.nextInt();
if (data % 2 == 0) {
evenCount++;
}else {
oddCount++;
}
}
if (oddCount % 2 == 0) { //说明奇数有偶数个
res[i] = (int)(Math.pow(2, evenCount) *
Math.pow(2, oddCount == 0 ? 0 :oddCount-1) % 1000000007); //这个公式一定一定要写对!
}else {
res[i] = 0;
}
}
scanner.close();
for (int i : res) {
System.out.println(i);
}
}
}
来源:(https://www.lanqiao.cn/problems/3535/learning/?subject_code=2&group_code=4&match_num=14&match_flow=1&origin=cup)