• Educational Codeforces Round 9 题解


    A

    比较阅读理解。。读懂了还好

    int n, p;
    std::vector<std::string> vs;
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> p;
        rep (i, 1, n) {
            std::string s; cin >> s;
            vs.push_back(s);
        }
        std::reverse(ALL(vs));
        lli apples = 0;
        lli ans = 0;
        for (auto s : vs) {
            if (s.size() == 8) {
                // halfplus
                lli last_apples = apples * 2 + 1;
                ans += apples * p + (p / 2);
                apples = last_apples;
            } else {
                // half
                lli last_apples = apples * 2;
                ans += apples * p;
                apples = last_apples;
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    B

    枚举翻转哪个位置的前缀,用前缀和算一算就行了。后缀同理。

    const int MAXN = 5e5 + 10;
     
    int n;
    lli pp[MAXN];
    char ss[MAXN];
    int seq[MAXN];
    lli pref[MAXN][2];
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        rep (i, 1, n) cin >> pp[i];
        cin >> ss;
        rep (i, 0, n - 1) seq[i + 1] = (ss[i] == 'B');
     
        lli ans = 0;
        rep (cas, 0, 1) {
            rep (i, 1, n) rep (j, 0, 1) pref[i][j] = pref[i - 1][j] + (seq[i] == j) * pp[i];
            ans = std::max(ans, pref[n][1]);
            rep (i, 1, n) {
                lli allans = pref[n][1];
                allans -= pref[i][1]; allans += pref[i][0];
                ans = std::max(ans, allans);
            }
            std::reverse(seq + 1, seq + 1 + n);
            std::reverse(pp + 1, pp + 1 + n);
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    C

    经典贪心。

    const int MAXN = 5e4 + 10;
     
    int n;
    std::string ss[MAXN];
     
    bool cmp(std::string sa, std::string sb) {
        return sa + sb < sb + sa;
    }
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        rep (i, 1, n) cin >> ss[i];
        std::sort(ss + 1, ss + 1 + n, cmp);
        rep (i, 1, n) cout << ss[i];
        cout << endl;
        return 0;
    }
    

    D. Longest Subsequence

    基础数论题,然而我不会。

    首先 (> m) 的数都可以扔了,这样我们可以把数据范围缩到 (10^6)

    接下来考虑算贡献:记录每个数字能对哪些 lcm 产生贡献,也就是对于 (i in [1, m]),如果 (x|i) 那么让 (mathrm{ans}_i)(1)。这个东西可以用一个类似埃氏筛的东西优化,即对于一个 (x),让所有 (mathrm{ans}_{kx}(kx leq m)) 都加 (1)。重复的数字可以合并计算。

    时间复杂度 (O(mlog m)),虽然这个我也不知道咋来的。

    最开始没看到输出下标,然后看了好一会也没看出来样例为啥是对的。。。

    #易错警示:题目要输出什么一定好好看清。

    const int MAXN = 1e6 + 10;
     
    int n, m;
    std::vector<int> bwl[MAXN];
    int occ[MAXN];
    std::vector<int> nums;
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        n = read(); m = read();
        rep (i, 1, n) {
            int x = read();
            if (x > m) continue;
            bwl[x].push_back(i);
        }
        rep (i, 1, MAXN - 5) if (bwl[i].size()) nums.push_back(i);
        for (auto v : nums) {
            for (int j = 1; j * v <= m; ++j) {
                occ[j * v] += bwl[v].size();
            }
        }
        int tans = 1;
        for (int i = 1; i <= m; ++i) if (occ[i] > occ[tans]) tans = i;
        cout << tans << ' ' << occ[tans] << endl;
        std::vector<int> inds;
        for (auto v : nums) if (tans % v == 0) for (auto id : bwl[v]) inds.push_back(id);
        std::sort(ALL(inds));
        for (auto id : inds) cout << id << ' ';
        cout << endl;
        return 0;
    }
    
    

    E. Thief in a Shop

    一个很 nb 的做法。

    正着 DP 不好写考虑交换维度和答案:设 f[i][j] 表示考虑前 i 个物品,凑出价格为 j 最少需要多少个物品,第一维可以滚掉。一个很普通的完全背包。

    然而这么写连样例都过不去。

    问题在于,题目让我们求的是恰好 (k) 个物品的情况,但是这么 DP 只能算出 (leq k) 个物品的情况。如果有价格为 (0) 的物品的话,不足 (k) 个物品也能通过 (0) 价格物品来补齐,但是这里没有 (0)

    于是考虑造出一个 (0) 来。

    (v = min a_i),接下来把所有物品的价格都减掉 (v),此时我们就成功获得了一个 (0) 价格物品!对修改过价格的物品做背包,我们可以知道每一种(修改后的)价格最少需要多少物品凑出来,如果 (leq k) 就说明这个(修改后的)价格是合法的。

    注意到所有物品的价格都被减掉了 (v),那么选 (k) 个物品时价格就被减掉了 (kv),所以输出答案的时候还要将价格加上 (kv)

    const int MAXN = 1000 + 10;
     
    int n, k;
    int aa[MAXN];
    int dp[MAXN * MAXN];
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        n = read(); k = read();
        rep (i, 1, n) aa[i] = read();
        std::sort(aa + 1, aa + 1 + n);
        rep (i, 2, n) aa[i] -= aa[1];
        memset(dp, 0x3f, sizeof dp);
        dp[0] = 0;
        rep (i, 2, n) {
            rep (j, aa[i], aa[n] * k) {
                dp[j] = std::min(dp[j], dp[j - aa[i]] + 1);
            }
        }
        rep (i, 0, aa[n] * k) {
            if (dp[i] <= k) {
                cout << i + aa[1] * k << ' ';
            }
        }
        cout << endl;
        return 0;
    }
    

    F. Magic Matrix

    首先可以把题目转化成对于每个点 ((i, j)),求第 (i) 行和第 (j) 行每列元素对应取 max 是否都大于 ((i, j))

    考虑确定当前值后将其他元素变为“大于为 1 小于为 0”这样一个思想,我们对于每一个节点 ((i, j)),将所有大于等于它的数字变成 (0),小于它的数字变成 (1),那么题设就转化成了第 (i) 行和第 (j) 行按位与起来是否不为 0.

    接下来再用边插入边查询的思想,按权值从小到大依次考虑所有节点,将已经考虑过的节点设置为 1(一起处理所有相同权值的节点),对当前节点查询第 (i) 行和第 (j) 行按位与起来是否不为 0 即可。这个过程可以用 bitset 优化,时间复杂度 (O(n^3/64)).

    const int MAXN = 2500 + 10;
     
    int n;
    int aa[MAXN][MAXN];
     
    std::bitset<MAXN> mat[MAXN];
     
    bool checksym() {
        for (int i = 1; i <= n; ++i) if (aa[i][i]) return false;
        rep (i, 1, n) rep (j, 1, n) if (aa[i][j] != aa[j][i]) return false;
        return true;
    }
     
    struct Node {
        int i, j, x;
    } nodes[MAXN * MAXN]; int cnt;
     
    bool cmp(Node x, Node y) { return x.x < y.x; }
     
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        n = read();
        rep (i, 1, n) rep (j, 1, n) aa[i][j] = read();
        if (!checksym()) {
            cout << "NOT MAGIC" << endl;
            return 0;
        }
        rep (i, 1, n) rep (j, 1, n) {
            nodes[++cnt] = {i, j, aa[i][j]};
        }
        std::sort(nodes + 1, nodes + 1 + cnt, cmp);
        for (int i = 1; i <= cnt; ++i) {
            int r = i;
            while (r + 1 <= cnt && nodes[i].x == nodes[r + 1].x) ++r;
            for (int x = i; x <= r; ++x) {
                int a = nodes[x].i, b = nodes[x].j;
                if ((mat[a] & mat[b]).any()) {
                    // mat[i][j] = 0 if AA[i][j] > AA[a][b]
                    cout << "NOT MAGIC" << endl;
                    return 0;
                }
            }
            for (int x = i; x <= r; ++x) mat[nodes[x].i][nodes[x].j] = 1;
            i = r;
        }
        cout << "MAGIC" << endl;
        return 0;
    }
    
    
  • 相关阅读:
    基于物品的协同过滤推荐算法
    监督学习与非监督学习的区别
    深入了解当前ETL的一些基本技术
    基于hadoop的图书推荐
    基于KNN的相关内容推荐
    KNN算法的补充
    Confluence 6 升级中的一些常见问题
    Confluence 6 升级以后
    Confluence 6 在升级之前
    Windows 独立启动方式安装 Archiva
  • 原文地址:https://www.cnblogs.com/handwer/p/15476718.html
Copyright © 2020-2023  润新知