容斥原理
如上图所示:
∣
s
1
∪
s
2
∪
s
3
∣
=
∣
s
1
∣
+
∣
s
2
∣
+
∣
s
3
∣
−
∣
s
1
∩
s
2
∣
−
∣
s
1
∩
s
3
∣
−
∣
s
2
∩
s
3
∣
+
∣
s
1
∩
s
2
∩
s
3
∣
\begin{aligned} |s_1 \cup s_2 \cup s_3|&=|s_1|+|s_2|+|s_3|-|s_1 \cap s_2|-|s_1 \cap s_3|-|s_2 \cap s_3|+|s_1 \cap s_2 \cap s_3| \end{aligned}
∣s1∪s2∪s3∣=∣s1∣+∣s2∣+∣s3∣−∣s1∩s2∣−∣s1∩s3∣−∣s2∩s3∣+∣s1∩s2∩s3∣
时间复杂度:
C
n
1
+
C
n
2
+
C
n
3
+
⋯
+
C
n
n
C_n^1+C_n^2+C_n^3+\cdots+C_n^n
Cn1+Cn2+Cn3+⋯+Cnn
因为
C
n
0
+
C
n
1
+
C
n
2
+
C
n
3
+
⋯
+
C
n
n
=
2
n
C_n^0+C_n^1+C_n^2+C_n^3+\cdots+C_n^n=2^n
Cn0+Cn1+Cn2+Cn3+⋯+Cnn=2n,等式的左右两边都是等于从n个中选任意多个数的方案,
2
2
2表示第
i
i
i个到底选不选的方案数,
2
n
2^n
2n就表示
n
n
n个中选不选对应数的方案数。
所以
C
n
1
+
C
n
2
+
C
n
3
+
⋯
+
C
n
n
=
2
n
−
C
n
0
=
2
n
−
1
C_n^1+C_n^2+C_n^3+\cdots+C_n^n=2^n-C_n^0=2^n-1
Cn1+Cn2+Cn3+⋯+Cnn=2n−Cn0=2n−1
同理存在等式:
C
k
1
−
C
k
2
+
C
k
3
−
C
k
4
+
⋯
+
(
−
1
)
k
−
1
C
k
k
=
1
C_k^1-C_k^2+C_k^3-C_k^4+\cdots+(-1)^{k-1}C_k^k=1
Ck1−Ck2+Ck3−Ck4+⋯+(−1)k−1Ckk=1
所以
∣
s
1
∪
s
2
∪
s
3
∣
=
∑
i
∣
s
i
∣
−
∑
i
⋅
j
∣
s
i
∩
s
j
∣
+
∑
i
j
k
∣
s
i
∩
s
j
∩
s
k
∣
−
⋯
|s_1\cup s_2 \cup s_3|=\sum_i|s_i|-\sum_{i \cdot j}|s_i \cap s_j|+\sum_{ijk}|s_i\cap s_j \cap s_k|-\cdots
∣s1∪s2∪s3∣=∑i∣si∣−∑i⋅j∣si∩sj∣+∑ijk∣si∩sj∩sk∣−⋯
能被整除的数
题解:
这里主要用二进制数表示某个数是否被选,1代表被选,0代表不被选,二进制中1的个数为奇数,说明为奇数个集合相交,前面的符号为+,反之为偶数个集合相交,前面的符号为-。
import java.io.*;
public class Main{
static int N=20;
static int[] p=new int[N];
public static void main(String[] args)throws IOException{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String[] strs=in.readLine().split(" ");
int n=Integer.parseInt(strs[0]);
int m=Integer.parseInt(strs[1]);
strs=in.readLine().split(" ");
for(int i=0;i<m;i++)p[i]=Integer.parseInt(strs[i]);
int res=0;
for(int i=1;i<(1<<m);i++){
int t=1;
int cnt=0;
for(int j=0;j<m;j++){
if((i>>j&1)==1){
cnt++;
if((long)t*p[j]>n){
t=-1;
break;
}
t=t*p[j];
}
}
if(t!=-1){
if(cnt%2==0)res-=n/t;
else res+=n/t;
}
}
System.out.println(res);
}
}