• 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;
    }
    
  • 相关阅读:
    MySQL与Oracle数据库差异对比
    阿里ECS服务器远程桌面访问报错
    单分派和多分派
    博客主题
    论文阅读:LIC-Fusion: LiDAR-Inertial-Camera Odometry
    如何科研(自动化所 张世峰)
    读论文
    SLAM十四讲第二版项目代码总结
    LeetCode 982. Triples with Bitwise AND Equal To Zero
    论文阅读:Visual-Inertial Localization With Prior LiDAR Map Constraints
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14306013.html
Copyright © 2020-2023  润新知