记录
题目来源
蓝桥杯官网的,题目链接
题意
表达式 ,将内层展开得,在展开就是
意思就是将数组中的每两项进行与操作,对他们进行求和
思路
讲解视频上说的是贡献法,之前碰到了子串分值和子串分值和的题目,也是用贡献法来解决的,大佬们的解释是只取对答案有正面作用的结果,反面作用的不考虑
举个例子,下面的数字是二进制形式
对于第一位(从右往左数的第一位)一共有4个1,从中选两个出来,一共有几种情况?组合数喽, 对于第二位一共有1个1,选不出来两个那就是0 对于第三位一共有3个1,能选出来 对于第四位一共有3个1,能选出来 思路就是将数组中每一个元素的1的位置存储起来,例如位权为上有几个1,若1的个数大于等于2,就算组合数即可。这里我描述的不太清楚,看代码可能会好理解点
代码
import java.util.*;
public class Main {
// 算组合数的,那个板子不太记得了,直接模拟
public static double one_Cnt(long m){
double res = 1;
int cnt =2;
while (cnt!=0){
res = res*m;
m--;
cnt--;
}
res/=2; //因为是从n中选两个,所以分母固定就是2
return res;
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int len = s.nextInt();
int[] data = new int[len];
long res =0;//存储结果的,选long类型是可能会爆int
for(int i=0;i<data.length;i++)
{
data[i] = s.nextInt();
}
// number[i] 表示第i位上A1-An的二进制表示中有多少个1
long[] number = new long[33];
for(int i=31;i>=0;i--){//题目保证数据范围是在int类型内,int类型32位,最多只需要右移31位
for(int j=0;j<len;j++)
// 位运算技巧,如果你想取得数字a的第2位数字,那么只用将a右移1位再与一下,或者和0异或一下也行
number[i] = number[i] + ((data[j]>>i) & 1);
}
for(int i=31;i>=0;i--){
if(number[i]>=2){
res+=one_Cnt(number[i]);
}
}
System.out.println(res);
s.close();
}
}