容斥原理(数论)

容斥原理

容斥原理(数论)_第1张图片
如上图所示:
∣ 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} s1s2s3=s1+s2+s3s1s2s1s3s2s3+s1s2s3
时间复杂度:
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=2nCn0=2n1

同理存在等式: 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 Ck1Ck2+Ck3Ck4++(1)k1Ckk=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 s1s2s3=isiijsisj+ijksisjsk

能被整除的数

容斥原理(数论)_第2张图片

题解:

这里主要用二进制数表示某个数是否被选,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);
    }
}

你可能感兴趣的:(算法学习,java,算法)