• Goolge Kick Start Round A 2020 (A ~ D题题解)


    比赛链接:kick start Round A 2020

    A. Allocation

    题目链接

    题意

    给出 (N) 栋房子的价格,第 (i) 栋房子的价格为 (A_i),你有 (B) 美元,问最多可以买多少栋房子?

    思路

    典型的贪心问题,将所有的房子按价格从低到高排序后选取即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 10;
    int _, Case;
    void solve() {
        Case++;
        int n, b;
        cin >> n >> b;
        int a[n];
        for (int i = 0; i < n; ++i) cin >> a[i];
        sort(a, a + n);
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            if (b < a[i])
                break;
            else
                b -= a[i], ans++;
        }
        cout << "Case #" << Case << ": " << ans << endl;
    }
    int main() {
        // freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        cin >> _;
        while (_--) solve();
    }
    

    B. Plates

    题目链接

    题意

    (N) 叠盘子,每叠有 (K) 个盘子,每个盘子有个 beauty value,现在要拿 (P) 个盘子,使得 beauty value 之和最大。拿盘子的条件:如果一个盘子的上面的盘子都被拿走了,才能拿到这个盘子。

    思路

    本题有一点点像多重背包。首先计算每叠盘子各自的前缀和 (sum[N][K]),设 (dp[i][j]) 表示前 (i) 堆盘子中取 (j) 个盘子的 beauty value 的最大值,转移方程为:

    [dp[i][j]=max{dp[i][j],dp[i−1][j−l]+sum[i][l]| for l ∈ [0,min(j,k)]} ]

    代码

    #include <bits/stdc++.h>
    #define ms(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int N = 1510;
    int _, Case = 0;
    int n, p, k, x;
    int sum[N][N], a[N][N], dp[N][N];
    void solve() {
        ms(sum, 0), ms(a, 0), ms(dp, 0);//初始化
        cin >> n >> k >> p;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= k; ++j) cin >> a[i][j];
        cout << "Case #" << ++Case << ": ";
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= k; ++j) sum[i][j] = sum[i][j - 1] + a[i][j];
        for (int i = 0; i <= k; ++i) dp[1][i] = sum[1][i];
        for (int i = 2; i <= n; ++i)
            for (int j = 1; j <= p; ++j)  //这里不需要太大,到p就够了
                for (int l = 0; l <= min(j, k); ++l)//接下来就是写状态转移方程了
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - l] + sum[i][l]);
    
        cout << dp[n][p] << endl;
    }
    int main() {
        // freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        for (cin >> _; _; _--) solve();
    }
    

    C. Workout

    题目链接

    题意

    给定 (N) 个严格递增的数,往这 (N) 个数中间插 (K) 个数,插入后要使所有的数仍然保持严格递增,而且要保证相邻两数的最大绝对值之差最小,求最小的绝对值之差。

    思路

    想了挺久的,最后二分过的,典型的最大值最小的问题。判断函数的思路:传入参数 (x),表示答案为 (x),然后遍历每个数 (num[i]),如果 (num[i+1]−num[i]>x),就插入 (num[i]+x),如果插入的数的个数大于 (K) 个就返回 false,否则返回 true。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const int N = 1e5 + 10;
    int _, Case;
    int n, k;
    ll tmp[N], a[N];
    bool check(int x) {
        int cnt = 0;
        for (int i = 0; i < n - 1; ++i)
            while (tmp[i + 1] - tmp[i] > x) tmp[i] += x, cnt++;
        if (cnt > k) return false;
        return true;
    }
    void solve() {
        cin >> n >> k;
        for (int i = 0; i < n; ++i) cin >> a[i];
        cout << "Case #" << ++Case << ": ";
        int l = 1, r = inf;
        while (l < r) {
            int mid = (l + r) >> 1;
            for (int i = 0; i < n; ++i) tmp[i] = a[i];
            if (check(mid))
                r = mid;
            else
                l = mid + 1;
        }
        cout << r << endl;
    }
    int main() {
        // freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        for (cin >> _; _; _--) solve();
    }
    

    D. Bundling

    题目链接

    题意

    给定 (N) 个字符串,把它们分组,每组 (K) 个。每组的分数是该组所有字符串的最长公共前缀。求最大的所有组的分数和。

    思路

    很容易想到前缀树 (字典树 / trie 树,相关算法讲解),建完树后从根节点 dfs,同时记录深度 d,然后从叶子节点回溯,统计每个节点出现的个数 cnt,如果某个节点 (u)(cnt[u]≥K),那么说明有 K 个字符串的前缀是以该节点结尾,深度 d 表示它们的前缀的长度,由于是从叶子节点回溯的,所以一定是最长公共前缀,所以 (ans=ans+d),同时 (cnt[u]) 减去 (k),即这 (k) 个字符串已经分完组,不再分到其他组。

    代码

    #include <bits/stdc++.h>
    #define ms(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const int N = 1e5 + 10;
    
    int trie[N << 2][30], tot = 1;
    int cnt[N << 2], n, k, _, Case;
    ll ans;
    string s;
    
    void init() { ms(trie, 0), ms(cnt, 0), tot = 1, ans = 0; }
    void insert(string s) {
        int p = 0;
        for (auto c : s) {
            int idx = c - 'A';
            if (!trie[p][idx]) trie[p][idx] = tot++;
            p = trie[p][idx];
        }
        ++cnt[p];
    }
    void dfs(int u, int d) {  //起点,深度
        for (int v = 0; v < 26; ++v) {
            if (trie[u][v]) {
                dfs(trie[u][v], d + 1);
                cnt[u] += cnt[trie[u][v]];
            }
        }
        ans += cnt[u] / k * d, cnt[u] %= k;
    }
    void solve() {
        init();
        cout << "Case #" << ++Case << ": ";
        cin >> n >> k;
        for (int i = 0; i < n; ++i) cin >> s, insert(s);
        dfs(0, 0);
        cout << ans << endl;
    }
    int main() {
        // freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        for (cin >> _; _; _--) solve();
    }
    

    这是第一次做Google平台的比赛,感觉难易度适中(适合我这种蒟蒻,感觉以后可以多写写)

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    第二次冲刺阶段第四天
    第二次冲刺阶段第三天
    第二次冲刺阶段第二天
    人月神话阅读笔记03
    第二次冲刺阶段第一天
    学习进度条(十二)
    课堂练习-找水王
    学习进度条(十一)
    学习进度表第十周
    构建之法阅读笔记06
  • 原文地址:https://www.cnblogs.com/RioTian/p/13960635.html
Copyright © 2020-2023  润新知