Codeforces Round #661 (Div. 3)

A. Remove Smallest

大意:

給出n個數,每次可以選擇兩個差小於等於1的數,然後刪掉其中的任意一個,問最後能不能只剩下一個元素

思路:

直接看有沒有兩個點的差大於2即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, a[55];
int main() {
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        sort(a, a + n);
        int flag = 1;
        for (int i = 1; i < n; i++) {
            if (a[i] - a[i - 1] > 1) flag = 0;
        }
        if (flag)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

B. Gifts Fixing

大意:

給出兩個長度爲n的數組a和b,每次可以選擇將\(a_i\)減一或者是\(b_i\)減一或者是\(a_i\)\(b_i\)同時減一

問經過最少多少次操作可以使得所有的a都相同,所有的b都相同

思路:

最少肯定是減到a的最小值和b的最小值

所以對於每個i先同時減到a和b的最小值,然後再單獨減即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, a[N], b[55];
int main() {
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int mina = 0x3f3f3f3f, minb = 0x3f3f3f3f;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            mina = min(mina, a[i]);
        }
        for (int i = 0; i < n; i++) {
            cin >> b[i];
            minb = min(minb, b[i]);
        }
        LL res = 0;
        for (int i = 0; i < n; i++) {
            int tmp1 = a[i] - mina;
            int tmp2 = b[i] - minb;
            int tmp3 = min(tmp1, tmp2);
            res += tmp3;
            tmp1 -= tmp3;
            tmp2 -= tmp3;
            res += max(tmp1, tmp2);
        }
        cout << res << endl;
    }
    return 0;
}

C. Boats Competition

大意:

給出n個數,求一個數s,使得數組中能找到兩個數相加等於s的對數最多,輸出這個對數

思路:

因爲n很小且每個數都小於n,所以可以枚舉s,求一共有多少對數相加爲s,這裏記錄每個數出現了多少次,然後直接算即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, a[55], num[55];
int main() {
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        memset(num, 0, sizeof num);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            num[a[i]]++;
        }
        int res = 0;
        for (int k = 1; k <= 100; k++) {
            int tmp = 0;
            for (int i = 1; i <= n; i++) {
                for (int j = i; j <= n; j++) {
                    if (i + j == k) {
                        if (i == j)
                            tmp+=num[i] / 2;
                        else
                            tmp+=min(num[i],num[j]);
                    }
                }
            }
            res = max(res, tmp);
        }
        cout << res << endl;
    }
    return 0;
}

D. Binary String To Subsequences

大意:

給出一個長度爲n的01字符串,問最少分成多少個子序列,使得每個序列都是0和1的交替

思路:

兩個隊列維護0和1結尾的子序列的編號,對於\(s[i]==1\),就去維護結尾爲0的隊列看有沒有編號,有的話直接把它刪掉,然後加到結尾爲1的隊列中,否則生成一個新的子序列放到結尾爲1的隊列中,反之亦然

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;
typedef long long LL;
int t, f[N], len[N];
int main() {
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        string s;
        cin >> s;
        int cnt = 0;
        queue<int> q0, q1;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '1') {
                if (!q0.empty()) {
                    f[i] = q0.front();
                    q0.pop();
                } else
                    f[i] = ++cnt;
                q1.push(f[i]);
            }
            if (s[i] == '0') {
                if (!q1.empty()) {
                    f[i] = q1.front();
                    q1.pop();
                } else
                    f[i] = ++cnt;
                q0.push(f[i]);
            }
        }
        cout << cnt << endl;
        for (int i = 0; i < s.size(); i++) {
            cout << f[i] << ' ';
        }
        cout << endl;
    }
    return 0;
}

E1. Weights Division (easy version)

大意:

給出一顆樹,現在每次可以將一條邊的權除以2,問至少需要幾次纔可以使得根節點到每個葉節點的權值和小於s

思路:

dfs處理出來每條邊經過多少次,然後將每條邊修改一次能貢獻多少權值加入優先隊列,然後每次取出優先隊列第一個邊,將其除以二再加入隊列即可

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;
typedef long long LL;
int t;
struct node {
    LL cnt, w;
};
LL sum;
LL times[N];
struct cmp {
    bool operator()(node a, node b) {
        return (a.w - a.w / 2) * a.cnt < (b.w - b.w / 2) * b.cnt;
    }
};

vector<pair<LL, LL> > mp[N];
priority_queue<node, vector<node>, cmp> q;
void dfs(int now, int fa, LL noww) {
    if (mp[now].size() == 1) times[now]++;
    // cout << now << endl;
    for (int i = 0; i < mp[now].size(); i++) {
        int ne = mp[now][i].first;
        LL w = mp[now][i].second;
        if (ne == fa) continue;
        dfs(ne, now, w);
        times[now] += times[ne];
    }
    node tmp;
    tmp.cnt = times[now];
    tmp.w = noww;
    q.push(tmp);
    sum += tmp.cnt * tmp.w;
}

int main() {
    cin >> t;
    while (t--) {
        int n;
        LL s;
        cin >> n >> s;
        while (!q.empty()) q.pop();
        for (int i = 1; i <= n; i++) {
            mp[i].clear();
            times[i] = 0;
        }
        sum = 0;
        for (int i = 0; i < n - 1; i++) {
            int x, y;
            LL w;
            cin >> x >> y >> w;
            mp[x].push_back(make_pair(y, w));
            mp[y].push_back(make_pair(x, w));
        }
        dfs(1, 0, 0);
        int res = 0;
        //cout << sum << endl;
        while (sum > s) {
            node now = q.top();
            q.pop();
            //cout << now.cnt << ' ' << now.w << endl;
            sum -= now.cnt * (now.w - now.w / 2);
            now.w /= 2;
            q.push(now);
            res++;
        }
        cout << res << endl;
    }
    return 0;
}

E2. Weights Division (hard version)

大意:

在E1的基礎上,每條邊除以二的時候都會有花費,取值是1或2,問最少操作次數

思路:

將花費爲1和2的分別放到兩個隊列中,分別進行E1的操作,分別記錄兩個隊列每次操作可以刪去的值

然後遍歷隊列1,二分找到相應的需要刪掉花費爲2的操作數量,取min即可\

注意兩個隊列分別可能爲空的特判

#include <bits/stdc++.h>

using namespace std;

const int N = 2e6 + 5;
typedef long long LL;
int t;
struct node {
    LL cnt, w;
    int to, cost;
};
LL sum;
LL times[N];
struct cmp {
    bool operator()(node a, node b) {
        return (a.w - a.w / 2) * a.cnt < (b.w - b.w / 2) * b.cnt;
    }
};
LL sub1[2 * N], sub2[2 * N];
vector<node> mp[N];
priority_queue<node, vector<node>, cmp> q1;
priority_queue<node, vector<node>, cmp> q2;
void dfs(int now, int fa, LL noww, int cost) {
    if (mp[now].size() == 1) times[now]++;
    // cout << now << endl;
    for (int i = 0; i < mp[now].size(); i++) {
        int ne = mp[now][i].to;
        LL w = mp[now][i].w;
        int c = mp[now][i].cost;
        if (ne == fa) continue;
        dfs(ne, now, w, c);
        times[now] += times[ne];
    }
    node tmp;
    tmp.cnt = times[now];
    tmp.w = noww;
    if (cost == 1)
        q1.push(tmp);
    else if (cost == 2)
        q2.push(tmp);
    sum += tmp.cnt * tmp.w;
}

int main() {
    cin >> t;
    while (t--) {
        int n;
        LL s;
        cin >> n >> s;
        while (!q1.empty()) q1.pop();
        while (!q2.empty()) q2.pop();
        for (int i = 1; i <= n; i++) {
            mp[i].clear();
            times[i] = 0;
        }
        sum = 0;
        for (int i = 0; i < n - 1; i++) {
            int x, y, c;
            LL w;
            cin >> x >> y >> w >> c;
            mp[x].push_back({0, w, y, c});
            mp[y].push_back({0, w, x, c});
        }
        dfs(1, 0, 0, 0);
        int step1 = 1;
        sub1[0] = 0;
        // cout << sum << endl;
        LL sum1 = sum;
        while (sum1 > s && !q1.empty()) {
            node now = q1.top();
            q1.pop();
            if (now.w == 0) break;
            // cout << now.cnt << ' ' << now.w << endl;
            sum1 -= now.cnt * (now.w - now.w / 2);
            sub1[step1] = sub1[step1 - 1] + now.cnt * (now.w - now.w / 2);
            now.w /= 2;
            q1.push(now);
            step1++;
        }
        LL sum2 = sum;
        int step2 = 1;
        sub2[0] = 0;
        while (sum2 > s && !q2.empty()) {
            node now = q2.top();
            q2.pop();
            if (now.w == 0) break;
            // cout << now.cnt << ' ' << now.w << endl;
            sum2 -= now.cnt * (now.w - now.w / 2);
            sub2[step2] = sub2[step2 - 1] + now.cnt * (now.w - now.w / 2);
            now.w /= 2;
            q2.push(now);
            step2++;
        }
        if (sum <= s) {
            cout << "0" << endl;
            continue;
        }
        int res = 0x3f3f3f3f;
        if (step2 == 1) {
            for (int i = 0; i < step1; i++) {
                if (sum - sub1[i] <= s) {
                    res = i;
                    break;
                }
            }
        } else if (step1 == 1) {
            for (int i = 0; i < step2; i++) {
                if (sum - sub2[i] <= s) {
                    res = 2 * i;
                    break;
                }
            }
        } else {
            for (int i = 0; i < step1; i++) {
                int pos =
                    lower_bound(sub2, sub2 + step2, sum - s - sub1[i]) - sub2;
                if (pos == step2) continue;
                res = min(res, i + 2 * pos);
            }
        }

        cout << res << endl;
    }
    return 0;
}

F. Yet Another Segments Subset

大意:

給出n個區間,要求最多的一個區間集合,滿足集合內任意兩個區間,要麼是互不相交,要麼是完全包含

思路:

區間dp,首先算出和這個區間的左右端點相同的區間數量,然後枚舉中點更新即可

注意需要離散化

#include <bits/stdc++.h>

using namespace std;

const int N = 6e3 + 5;
typedef long long LL;
int t;
struct node {
    int l, r;
} a[N];
vector<int> v;
int getx(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin(); }
bool cmp(node a, node b) {
    if (a.l == b.l) return a.r < b.r;
    return a.l < b.l;
}
vector<int> pos[N];
int f[N][N];

int dp(int l, int r) {
    if (f[l][r] != -1) return f[l][r];
    f[l][r] = 0;
    int self = count(pos[l].begin(), pos[l].end(), r);
    if (l == r)
        f[l][r] = self;
    else
        f[l][r] = self + dp(l + 1, r);
    for (int i = l; i < r; i++) {
        f[l][r] = max(self + dp(l, i) + dp(i + 1, r), f[l][r]);
    }
    return f[l][r];
}

int main() {
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        v.clear();
        for (int i = 0; i < n; i++) {
            int l, r;
            cin >> l >> r;
            a[i].l = l, a[i].r = r;
            v.push_back(l);
            v.push_back(r);
        }
        sort(v.begin(), v.end()), v.erase(unique(v.begin(), v.end()), v.end());
        int m = v.size();
        for (int i = 0; i < m; i++) {
            pos[i].clear();
            for (int j = 0; j < m; j++) {
                f[i][j] = -1;
            }
        }
        for (int i = 0; i < n; i++) {
            a[i].l = getx(a[i].l);
            a[i].r = getx(a[i].r);
            pos[a[i].l].push_back(a[i].r);
        }

        cout << dp(0, m - 1) << endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章