容斥定理

斥原理可以描述如下:

         要計算幾個集合並集的大小,我們要先將所有單個集合的大小計算出來,然後減去所有兩個集合相交的部分,再加回所有三個集合相交的部分,再減去所有四個集合相交的部分,依此類推,一直計算到所有集合相交的部分。

簡單來說,就是奇加偶減。

 

舉個例子:

求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;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章