题目:
题目思路:
首先我们知道a数组中所有值的和为m
我们要求a数组中所有值异或的值最大的情况数
我们要先抓住题目的第一个条件
(使a数组中所有值的异或的值为最大)
【对于异或还不清楚的同学可以网上学习一下】
我们要想使异或的值最大
就要保证越高位的数上面位1可以使异或为最大
例如当m=4,n=2时
那么它的二进制为 100
我们可以取
a中的数组为
a1={4,0} (二进制为{100,000})
异或结果为 100【二进制】十进制:4
a2={3,1} (二进制为{011,001})
异或结果为 010【二进制】十进制:2
a1={2,2} (二进制为{010,010})
异或结果为 000【二进制】十进制:0
注:二进制只写了三位
我们可以推出(大家可以自己举更多的例子去了解一下2二进制的规律)
要想使所有的异或结果最大
可以通过观察规律得出异或的最大值就为m自己
然后根据条件2(a数组中有n个数)进行如下步骤
具体操作:
1.先就取m的二进制上的所有数为a数组的一个数,数组里面其他数皆为0。
(该情况为能取异或后为最大值的一种情况)
2.在保证位数上0和1改变数字的情况可以对其进行改变所在的数组的数
例如:m=5,n=2;
我们取异或最大的情况可以取这两种类型的数组
a1={5,0}(二进制为{101,000})
异或结果为 101【二进制】十进制:5
a1={4,1} (二进制为{100,001})
异或结果为 101【二进制】十进制:5
3.在确定了步骤1和步骤2的情况下(即每个位上的数为0或1)
我们再观察变量n
通过二进制的规律我们可以得到:
每个位上1移动到数组中的另外一个数会使数组形成新的方案数
对于每个位上的1我们可以移动到数组a中n个数中的任意一个数
那么我们可以得出一个位上的1移动会造成n种情况
(注:对于0的移动不会影响每个数的大小所以不考虑)
4.确定了思路我们就可以将思路写成代码
我们这里还需要知道对于二进制位数操作的一些方法
【1】一个数的二进制 向右边移动1位(去掉最右边的一位) 即为这个数除以2
【2】可以通过&1来判断最后一位是否为1(二进制最右边为1则为奇数,为0则为偶数)
代码详解:
#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
#include<string>
const int N=(ll)1e9+7;
int main()
{
ll n,m;
scanf("%lld%lld",&n,&m);
n%=N;//按题目要求对n取模
ll s=1;
while(m)//对m的二进制上每个位上的数考虑
{
if(m&1) s=s*n%N;//如果二进制的最后一位为1(m为奇数)那么就进行方案数统计
m=m>>1;//向右边移动一位(对m除以2)进行下一位的判断
}
cout<<s;//输出答案
return 0;
}
PS:大家对于二进制感兴趣的可以更多取了解一下0和1的奥秘,另外博客中所写的内容不怎么理解的可以自己多举几个例子来摸索其中的规律,这会帮你理解博客,谢谢阅读,不妨给个三连,嘿嘿(/doge)。