• 每日构造/DP(4.21)


    C - ThREE

    先考虑如果是一条链怎么做,直接模三分类填就行

    现在转换到树上,那不妨先对整棵树红蓝交替染色,假设最终红蓝点个数分别为 \(Rnum\)\(Bnum\)\(1 \sim n\) 模 3 余 1、2、0 的个数分别为 \(n_1\)\(n_2\)\(n_3\)

    因此构造染色方法:

    • \(Rnum < n_3\) :红点全放 \(mod \space 3 \equiv 0\) 的点,剩下的数全塞蓝点
    • \(Rnum > n_1 + n_3\) :蓝点全放 \(mod \space 3 \equiv 0\) 的点,剩下的数全塞红点
    • \(others\) :红点放 \(mod \space 3 \equiv 1\) 的点,蓝点放 \(mod \space 3 \equiv 2\) 的点,最后还空着的点就放 \(mod \space 3 \equiv 0\) 的数
    #include <bits/stdc++.h>
    #define IOS                           \
        std::ios::sync_with_stdio(false); \
        std::cin.tie(0);                  \
        std::cout.tie(0);
    
    int main()
    {
        IOS;
        int n;
        std::cin >> n;
        std::vector<int> p(n + 1);
        std::queue<int> q[2]; // 0 红 1 蓝
        std::vector<std::vector<int>> g(n + 1);
        for (int i = 1, u, v; i < n; ++i)
        {
            std::cin >> u >> v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        std::function<void(int, int, int)> dfs = [&](int u, int fa, int col)
        {
            q[col].push(u);
            for (auto v : g[u])
                if (v != fa)
                    dfs(v, u, col ^ 1);
        };
        dfs(1, 0, 0);
        int Rnum = q[0].size(), Bnum = q[1].size();
        int n1 = (n - 1) / 3 + 1, n2 = (n - 2) / 3 + 1, n3 = n / 3;
        if (Rnum < n3)
        {
            int x = 1;
            while (q[0].size() && 3 * x <= n)
            {
                p[q[0].front()] = 3 * x;
                q[0].pop();
                ++x;
            }
            while (q[1].size() && 3 * x <= n)
            {
                p[q[1].front()] = 3 * x;
                q[1].pop();
                ++x;
            }
            x = 0;
            while (q[1].size() && 3 * x + 1 <= n)
            {
                p[q[1].front()] = 3 * x + 1;
                q[1].pop();
                ++x;
            }
            x = 0;
            while (q[1].size() && 3 * x + 2 <= n)
            {
                p[q[1].front()] = 3 * x + 2;
                q[1].pop();
                ++x;
            }
        }
        else if (Rnum > n1 + n3)
        {
            int x = 1;
            while (q[1].size() && 3 * x <= n)
            {
                p[q[1].front()] = 3 * x;
                q[1].pop();
                ++x;
            }
            while (q[0].size() && 3 * x <= n)
            {
                p[q[0].front()] = 3 * x;
                q[0].pop();
                ++x;
            }
            x = 0;
            while (q[0].size() && 3 * x + 1 <= n)
            {
                p[q[0].front()] = 3 * x + 1;
                q[0].pop();
                ++x;
            }
            x = 0;
            while (q[0].size() && 3 * x + 2 <= n)
            {
                p[q[0].front()] = 3 * x + 2;
                q[0].pop();
                ++x;
            }
        }
        else
        {
            int x = 0;
            while (q[0].size() && 3 * x + 1 <= n)
            {
                p[q[0].front()] = 3 * x + 1;
                q[0].pop();
                ++x;
            }
            x = 0;
            while (q[1].size() && 3 * x + 2 <= n)
            {
                p[q[1].front()] = 3 * x + 2;
                q[1].pop();
                ++x;
            }
            x = 1;
            while (q[0].size() && 3 * x <= n)
            {
                p[q[0].front()] = 3 * x;
                q[0].pop();
                ++x;
            }
            while (q[1].size() && 3 * x <= n)
            {
                p[q[1].front()] = 3 * x;
                q[1].pop();
                ++x;
            }
        }
        for (int i = 1; i <= n; ++i)
            std::cout << p[i] << " ";
        return 0;
    }
    

    D. Flowers

    \(f[i]\) 表示 \(i\) 朵花有几种吃法,因为每次吃要么吃 1 朵红花要么吃 \(k\) 朵白花,因此有转移方程:

    \(f[i] = f[i-1] + f[i-k]\)

    最后因为问的是区间,所以作个前缀和就好。

    #include <bits/stdc++.h>
    #define IOS                           \
        std::ios::sync_with_stdio(false); \
        std::cin.tie(0);                  \
        std::cout.tie(0);
    using ll = long long;
    const int N = 1e5;
    const int P = 1e9 + 7;
    
    int main()
    {
        IOS;
        int t, k;
        std::cin >> t >> k;
        std::vector<ll> f(N + 1), s(N + 1);
        f[0] = 1;
        for (int i = 1; i <= N; ++i)
        {
            f[i] = f[i - 1] % P;
            if (i >= k)
                f[i] = (f[i] + f[i - k]) % P;
            s[i] = (s[i] + f[i]) % P;
        }
        for (int i = 1; i <= N; ++i)
            s[i] = (s[i - 1] + s[i]) % P;
        for (int i = 1, a, b; i <= t; ++i)
        {
            std::cin >> a >> b;
            std::cout << (s[b] - s[a - 1] + P) % P << std::endl;
        }
        return 0;
    }
    

    E. Pillars

    和昨天 \(div2\)\(D\) 有点像,都是用数据结构优化 dp 。

    \(f[i]\) 表示以 \(i\) 为结尾的子序列的最大长度,有转移方程:

    \(f[i] = \underset{1 \leq k \leq i-1}{max}f[k] + 1\)

    复杂度为 \(O(n^2)\) ,考虑优化

    方法和昨天那题差不多,就是先把 \(a\) 离散化后建一棵线段树维护区间最大值,唯一不同的是由于题目给的条件是绝对值,所以要找左右两个区间,大概就是下面这个样子:

    时间复杂度 \(O(nlogn)\)

    #include <bits/stdc++.h>
    #define IOS                           \
        std::ios::sync_with_stdio(false); \
        std::cin.tie(0);                  \
        std::cout.tie(0);
    #define PLL std::pair<ll, ll>
    using ll = long long;
    
    #define lson o << 1
    #define rson o << 1 | 1
    #define val first
    #define id second
    struct SegTree
    {
        const int n;
        std::vector<PLL> max;
        SegTree(int n) : n(n), max(n << 2 | 1){};
    
        PLL merge(PLL a, PLL b) { return a.val > b.val ? a : b; }
    
        void update(int o, int l, int r, int x, PLL y)
        {
            if (l == r)
            {
                max[o] = merge(max[o], y);
                return;
            }
            int mid = (l + r) >> 1;
            if (x <= mid)
                update(lson, l, mid, x, y);
            else
                update(rson, mid + 1, r, x, y);
            max[o] = merge(max[lson], max[rson]);
        }
    
        PLL query(int o, int l, int r, int x, int y)
        {
            if (x <= l && r <= y)
                return max[o];
            PLL res = {0, 0};
            int mid = (l + r) >> 1;
            if (x <= mid)
                res = merge(res, query(lson, l, mid, x, y));
            if (mid < y)
                res = merge(res, query(rson, mid + 1, r, x, y));
            return res;
        }
    };
    
    int main()
    {
        IOS;
        int n, d;
        std::cin >> n >> d;
        std::vector<ll> a(n + 1), b(n + 1), s(n + 1);
        for (int i = 1; i <= n; b[i] = a[i], ++i)
            std::cin >> a[i];
        std::sort(b.begin() + 1, b.begin() + n + 1);
        int nn = std::unique(b.begin() + 1, b.begin() + n + 1) - b.begin() - 1;
        // for (int i = 1; i <= n; ++i)
        //     a[i] = std::lower_bound(b.begin() + 1, b.begin() + nn + 1, a[i]) - b.begin() + 1;
        SegTree t(nn);
        std::vector<ll> f(n + 1);
        for (int i = 1, l, r, pos; i <= n; ++i)
        {
            l = std::upper_bound(b.begin() + 1, b.begin() + nn + 1, a[i] - d) - b.begin() + 1 - 1;
            r = std::lower_bound(b.begin() + 1, b.begin() + nn + 1, a[i] + d) - b.begin() + 1;
            PLL res1 = t.query(1, 1, nn, 1, l), res2 = t.query(1, 1, nn, r, nn);
            PLL res = res1.val > res2.val ? res1 : res2;
            f[i] = res.val + 1, s[i] = res.id;
            pos = std::lower_bound(b.begin() + 1, b.begin() + nn + 1, a[i]) - b.begin() + 1;
            t.update(1, 1, nn, pos, {f[i], i});
        }
        int ans = 0, pos = 0;
        for (int i = 1; i <= n; ++i)
            if (f[i] > ans)
                ans = f[i], pos = i;
        std::cout << ans << std::endl;
        std::vector<int> path;
        path.push_back(pos);
        while (s[pos])
        {
            path.push_back(s[pos]);
            pos = s[pos];
        }
        std::reverse(path.begin(), path.end());
        for (auto x : path)
            std::cout << x << " ";
        return 0;
    }
    
  • 相关阅读:
    6、深入理解计算机系统笔记:存储器层次结构,存储技术(1)
    流程图【占无内容】
    程序的三种基本控制架构【只有提纲】
    Console算法[for]穷举法:百钱买百鸡
    Logic算法(狼羊白菜)
    Console算法continue与break的区别?
    Console算法[for]简单画图
    Console算法[for]输出等腰三角形
    Console算法[for]国王与老人的六十四格
    Console算法[for]素数
  • 原文地址:https://www.cnblogs.com/Foreign/p/16178397.html
Copyright © 2020-2023  润新知