集合中的質數(容斥原理和dfs)

  • 註釋:當然這道題也可以二進制枚舉,只是不用0\small 0這個二進制。
  • 題面
  • 題意:見題面。
  • 解決思路
    容斥原理

    總結:容斥原理就是奇加偶減。
    有了公式就直接dfs\small dfs求解就可。
    變量的含義
    { pos:pos opt:(+11) mul:pos\small \begin{cases} \ pos:遍歷數組的第pos位\\ \ opt:容斥原理的符號(+1或-1)\\ \ mul:第pos位之前所選的數的乘積\\ \end{cases}
    從左往右遍歷每個數,對於這個數來說,可以取,也可以不取。
    不取:除了遍歷的位置加一,其餘不變。
    :遍歷的位置加一,由容斥原理的奇加偶減的性質可以得到,多取一個數,它肯定變號,所以opt\small opt加負號,當前的數乘u[pos]\small u[pos]
    會發現容斥原理至少取一個數,沒有不取數的情況,所以當遍歷到pos\small pos時,答案的貢獻必須算上取u[pos]\small u[pos]的情況,由於(mul:pos)\small (mul:第pos位之前所選的數的乘積),對答案的貢獻爲:m\small mmulu[pos]\small mul*u[pos]下取整。
    排序剪枝操作:發現題目,當數的乘積大於m\small m時,就對答案沒貢獻了,所以當遍歷到pos\small pos已經越界時,後面的數就可以不用遍歷了。
  • AC代碼
//優化
#pragma GCC optimize(2)
//C
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
//C++
#include<unordered_map>
#include<algorithm>
#include<iostream>
#include<istream>
#include<iomanip>
#include<climits>
#include<float.h>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
//宏定義
#define N 1010
#define DoIdo main
//#define scanf scanf_s
#define it set<ll>::iterator
#define TT template<class T>
#define cint const int 
//定義+命名空間
typedef long long ll;
typedef unsigned long long ull;
const int mod = 10007;
const ll INF = 1e18;
const int maxn = 1e6 + 10;
using namespace std;
//全局變量
ll n, m;
ll u[25];
ll ans = 0;
//函數區
ll max(ll a, ll b) { return a > b ? a : b; }
ll min(ll a, ll b) { return a < b ? a : b; }
ll loop(ll n, ll p) { return (n % p + p) % p; }
void dfs(ll pos, ll opt, ll mul) {
	//如果遍歷的數超過輸入的數,則返回
	if (pos == n + 1) return;
	//這就是u[pos] * mul <= m的變形
	//這樣可以預防long long溢出
	if (u[pos] <= m / mul) {
		//加一下對答案的貢獻
		ans += opt * m / (mul * u[pos]);
		//取的情況
		dfs(pos + 1, opt, mul);
		//不取的情況
		dfs(pos + 1, -opt, mul * u[pos]);
	}
	else return;
}
//主函數
int DoIdo() {

	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);

	cin >> n >> m;

	for (int i = 1; i <= n; i++) {
		cin >> u[i];
	}

	sort(u + 1, u + n + 1);
	dfs(1, 1, 1);

	cout << ans << endl;
	return 0;
}
//分割線---------------------------------QWQ
/*



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