1. 程式人生 > >容斥原理學習

容斥原理學習

1.何為容斥原理?

     在計數時,必須注意沒有重複,沒有遺漏。為了使重疊部分不被重複計算,人們研究出一種新的計數方法,這種方法的基本思想是:先不考慮重疊的情況,把包含於某內容中的所有物件的數目先計算出來,然後再把計數時重複計算的數目排斥出去,使得計算的結果既無遺漏又無重複,這種計數的方法稱為容斥原理

2.如何用容斥原理?

    結果的個數為一個集合的話,則算出所有集合,減去兩個集合重合的部分,加上三個集合重合的部分,減去四個集合重合的部分,以此類推。

    至於為何要加上三個集合的部分我們可以用溫恩圖來說明

   

  如圖 當我們減去兩兩相交的部分時,三個部分都重合的那個被減去了三次,因此需要加上一次。

3.例題

 hdu1796      大意是求 小於n 且能被m個數整除的數的個數;

#include<iostream>
using namespace std;
int a[100],ans,n,cc;
int gcd(int a,int b){
  return !b?a:gcd(b,a%b);
}

int lcm(int a,int b){
  return a/gcd(a,b)*b;
}

void dfs(int lc,int num,int i,int cnt){
   if(num==cnt){
     lc = (n-1)/lc;
     num&1?ans+=lc:ans-=lc;
     return ;
   }
   if (i>=cc) return;
   int tmp=lcm(lc,a[i]);
   dfs(tmp,num,i+1,cnt+1);
   if(num-cnt>cc-i-1) return;
   dfs(lc,num,i+1,cnt);
}

void cal(int m){
  int cnt= 0,tmp;
  ans=0;
  for (int i=0;i<m;i++){
    cin>>tmp;
    !tmp?tmp=0:a[cnt++]=tmp;
  }
  cc=cnt;
  for (int i=1;i<=cnt;i++){
    dfs(1,i,0,0);
  }
cout<<ans<<endl;
}
int main()
{
    int m;
    while(cin>>n>>m){
        cal(m);
    }
 return 0;
}
poj 3904