1.容斥原理
例题:890. 能被整除的数
如果暴力枚举的话肯定会超时,用容斥原理做。
以样例为例:
定义集合:
S2:1—10中所有能被 2 整除的数,也就是 2 的倍数的集合 {2,4,6,8,10}
S3:1—10中所有能被 3 整除的数,也就是 3 的倍数的集合 {3,6,9}
我们要求的就是 |S2∪S3| = |S1| + |S2| - |S2 ∩S3| = 5 + 3 - 1 = 7
现在题目是 p1,p2,…,pm
那我们要求的就是:
|Sp1∪Sp2∪Sp3∪…∪Spm| = |S1| + |S2| +…+|Sm| - 所有两两集合的交 + 所有三三集合的交 - … (奇数个集合就是正号,偶数个就是负号)
这是 m 个集合的运算
这个怎么求呢?用位运算
i:1----2m -1,把 i 看做 m 位的二进制串,每一位上,0表示不选这个集合,1表示选这个集合。所以,每个 i 就代表了这 m 个集合的一种选法。
import java.util.Scanner;
public class Main {
static int N = 20;
static int n;
static int m;
static int[] p = new int[N];//存m个质数
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for(int i = 0;i < m;i++) p[i] = sc.nextInt();
sc.close();
int res = 0;
for(int i = 1;i < 1 << m;i++) {
int t = 1, 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 *= p[j];
}
}
if(t != -1)<