题目链接:http://oj.daimayuan.top/course/22/problem/899
方法:常规思路为记录每一个数字出现的次数,然后再选出只出现一次的数,最后进行排序输出。但是这里不行,因为数据范围很大。所以我想到位运算。
xor的性质:a^a=0,两个相同的数进行异或,则会消为0,结合题意,我们将数组中的每一个数进行xor,最后会得到一个值M,然而出现偶数个的数,最终通过xor都消为了0,所以M=a^b。a,b分别为最后只出现一次的两个数。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int a[N];
int main(){
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int v=0;
for(int i=1;i<=n;i++) v^=a[i];
int c=0;
while(v){//找最高位1的位置:从右往左
c++;v>>=1;
}
int minn=0,maxx=0;
for(int i=1;i<=n;i++){
if((a[i]>>(c-1))&1) maxx^=a[i];
//最高位的1,一定是最后两个数中的较大值,依次xor,因为其他数会出现两次,所以最终只会剩下较大值
else minn^=a[i];//同理
}
cout<<minn<<" "<<maxx;
}
题目链接:http://oj.daimayuan.top/course/22/problem/948
题意:j&i=j,说明j是i的子集(想想&的性质)。其次是j<i,说明j是i的子集,但其中的子集是不等于i的。(因为i本身也是i的子集)
方法:理解题意后,书写公式即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
const int mod=1e9+7;
int n,f[N];
int main(){
cin>>n;f[0]=1;
for(int i=1;i<1<<n;i++){
f[i]=1;
for(int j=(i-1)&i;j;j=(j-1)&i){//枚举子集
f[i]+=f[j];f[i]%=mod;//书写题目公式
}
f[i]=1LL*f[i]*i%mod;//书写题目公式
}
for(int i=0;i<1<<n;i++) cout<<f[i]<<" ";
}