題意:
有\(n\)個問題,每一個問題的難度爲\(a_i\),最多選出三個問題\(x, y, z\),要求\(兩兩之間不能存在整除關係\),
求最多能得到多大難度的問題集,一個問題集的難度爲集合裏面全部問題難度的總和。c++
思路:
考慮從小到大枚舉一個數,而後用set維護加入的數,對於一個數\(x\),去掉它的全部因數,去找最大的那個\(y\),而後去掉\(y\)的全部因數,再找一個最大的\(z\),那麼這個\(x、y、z\)就是包含\(x\)以及比\(x\)小的數的可能性中最大的一種組合。spa
證實:
爲何不存在一個次小的\(y\)使得組合更大?
首先咱們知道,若是枚舉了\(x\),以及肯定了\(y\),那麼\(z\)必然是肯定的。
那麼咱們假設咱們不選最大的\(Y\),選一個次大的\(y\),那麼\(z\)一定是\(Y\)的因數,若是不是的\(Y\)的因數,那麼取
\(Y\)和\(z\)必然使得答案更優。
同理,也容易發現\(y\)也一定是\(Y\)的因數。
那麼在\(y\)與\(z\)都是\(Y\)的因數的狀況下,而且\(y \neq Y, z \neq Y\),那麼必然有\(y + z \leq Y\)。
因此確定是選擇最大的那個\(Y\)使得答案最優。code
代碼:it
#include <bits/stdc++.h> using namespace std; #define N 200010 int n, a[N]; vector < vector <int> > vec; int main() { vec.clear(); vec.resize(200005); for (int i = 1; i <= 200000; ++i) { for (int j = i + i; j <= 200000; j += i) { vec[j].push_back(i); } } int T; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", a + i); } sort(a + 1, a + 1 + n); n = unique(a + 1, a + 1 + n) - a - 1; int res = 0; map <int, int> mp; set <int, greater <int> > s; for (int i = 1; i <= n; ++i) { res = max(res, a[i]); for (auto it : vec[a[i]]) s.erase(it); mp[a[i]] = 1; if (!s.empty()) { int x = *s.begin(); res = max(res, a[i] + x); s.erase(x); for (auto it : vec[x]) s.erase(it); if (!s.empty()) { res = max(res, a[i] + x + *s.begin()); } for (auto it : vec[x]) if (mp.find(it) != mp.end()) s.insert(it); s.insert(x); } for (auto it : vec[a[i]]) if (mp.find(it) != mp.end()) s.insert(it); s.insert(a[i]); } printf("%d\n", res); } return 0; }