Codeforces 1183F Topforces Strikes Back

題意:
\(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;
}
相關文章
相關標籤/搜索