ACwing算法笔记ing
一.位运算的基本知识:
1.位运算符:
按位与 | & |
按位或 | | |
按位异或 | ^ |
取反 | ~ |
左移 | << |
右移 | >> |
二.左移右移运算符的应用:集合中的枚举:
题目:
给定一个整数 n和 m 个不同的质数 p1,p2,…,pm。
请你求出 1∼n中能被 p1,p2,…,pm中的至少一个数整除的整数有多少个。
1.首先根据容斥定理 :我们知道了能被p1整除的数的集合“P1”,知道了能被p2整除的数的集合P2,以此类推,我们知道了可以被pm整除的数的集合Pm;
所以1∼n中能被 p1,p2,…,pm中的至少一个数整除的整数:
(公式如有错误请指正);
2.集合的个数好说:可以用来算出可以整除Pi的个数,可以用
来算出来可以同时整除若干个公因子的个数;
但怎么枚举?用普通的搜索太麻烦了:
所以这里介绍一个位运算枚举所有组合的方法;
3.再观察一下res,我们发现所有的选法为:
4.就像我们在离散数学里学的极大项和极小项一样,我们用二进制来表示每一种组合:
如有8个质数: 可以表示为0000 1011 :
5.上代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=20;
int n,m;
int p[N];
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)cin>>p[i];
int res=0;
for(int i=1;i<1<<m;i++)
{
int t=1;
int s=0;
for(int j=0;j<m;j++){
if(i>>j&1)
{
if(p[j]*(LL)t>n)
{
t=-1;
break;
}
t*=p[j];
s++;
}
}
if(t!=-1){
if(s%2)res+=n/t;
else res-=n/t;
}
}
cout<<res<<endl;
return 0;
}