斥原理可以描述如下:
要計算幾個集合並集的大小,我們要先將所有單個集合的大小計算出來,然後減去所有兩個集合相交的部分,再加回所有三個集合相交的部分,再減去所有四個集合相交的部分,依此類推,一直計算到所有集合相交的部分。
簡單來說,就是奇加偶減。
舉個例子:
求1~n中多少個數不是2,3,5,7的倍數,當n=10,結果只有1一個數。
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int ans=n-(n/2+n/3+n/5+n/7)+(n/2/3+n/2/5+n/2/7+n/3/5+n/3/7+n/5/7)-(n/2/3/5+n/2/3/7+n/3/5/7+n/2/5/7)+n/2/3/5/7;
//ans=n-(n/2+n/3+n/5+n/7)+(n/6+n/10+n/14+n/15+n/21+n/35)-(n/30+n/42+n/105+n/70)+n/210
cout<<ans<<endl;
return 0;
}
例子2:
題目描述:
V_Dragon有n盞電燈泡,編號爲1-n,每個燈泡都有一個開關,那麼問題來了
1.所有燈泡初始時爲不亮的;
2.V_Dragon分別進行三次操作;
3.每次操作他都選一個質數x,將編號爲x和x的整數倍的燈泡的開關都撥動一下(如果燈爲亮,那麼撥動以後燈爲不亮,如果燈不亮,撥動以後變爲亮)
求最後亮着的燈的數量;
輸入:
輸入T表示T組測試數據(1<=T<=100)
接下來T組數據
每組第一行一個n表示燈泡各數(1<=n<=10^9)
第二行三個數a,b,c表示V_Dragon每次選擇的數(1<=a,b,c<=10^6)(a,b,c全爲質數且a,b,c兩兩互不相等)
輸出:
最後亮着的燈的個數
樣例輸入:
1
30
2 3 5
樣例輸出:
15
題解:
原來的方法:
a+b+c-(ab+ac+bc)+abc。這祥的話a+b+c代表的是啊a,b,c總的要按的燈的按鈕。
而ab,bc,ac代表的是按兩次或者兩次以上燈的數量。
這裏我們應該想一下,如果只是減一個ab+ac+bc的話,那就是三次所涉及的總共燈的數量,
但是對一個燈操作兩次,燈就關了。這祥就不需要計算這一塊了。所以應該減兩次ab+ac+bc。
再看+abc。我們將在前面已經-2*(ab+bc+ac)了,就相當於將abc這一塊減了三次,
但是對於abc這一塊,三次操作還是亮着的。所以應該加上4*(abc)。
所以最後的公式應該是a+b+c-2(ab+bc+ac)+4abc.
#include<iostream>
using namespace std;
int main()
{
int T,n,a,b,c;
cin>>T;
while(T--)
{
cin>>n;
cin>>a>>b>>c;
int sum=n/a+n/b+n/c-2*(n/a/b+n/b/c+n/a/c)+4*(n/a/b/c);
//int sum= n/a+n/b+n/c-2*( n/(a*b) + n/(b*c) + n/(a*c) )+4*( n/(a*b*c) )
//這裏 其實應該是n*gcd(a,b)/(a*b)...但是因爲題目中說a,b,c互質,所以gcd=1,但是如果題目中不說互質,就需要乘以gcd
cout<<sum<<endl;
}
return 0;
}