zoukankan      html  css  js  c++  java
  • Codeforces Round #693 (Div. 3) A~E 题解

    写在前边

    链接:Codeforces Round #693 (Div. 3)

    没有打,闲的没事补一下题。

    A. Cards for Friends

    链接:A题链接

    题目大意:

    给定一张(w*h)的卡片,每次可以切成(cfrac{w}{2} * h)或者(cfrac{h}{2} * w)的两张卡片,给定一个整数(n),问所给的大卡片是否切成至少(n)张卡片。

    思路

    一开始想的太复杂了,分情况讨论了半天还是WA,其实这题就是长和宽分别切就行,每符合题意切一次,(res *= 2),得到答案。

    代码:

    #include <iostream>
    
    using namespace std;
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            int w, h, n, res = 1;
            cin >> w >> h >> n;
            while (w % 2 == 0) {
                w /= 2;
                res *= 2;
            }
            while (h % 2 == 0) {
                h /= 2;
                res *= 2;
            }
            cout << (res >= n ? "YES" : "NO") << endl; 
        }
    
        return 0;
    }
    

    B. Fair Division

    链接:B题链接

    题目大意:

    给定(n)个糖果,每个糖果的重量是(1)或者(2),现在将糖果平分给两人,问是否能实现两个人分得的重量相同,注意:一个糖果不能分成两半。

    思路

    我的思路:求其总重量,看总重量是否能被2整除,若不能整除,那么肯定为("NO"),若能平分,那么我们只看一个人即可,将糖果从大到小排序,然后如果能正好分给一个人,那么剩下的就是第二个人的糖果了,会多用一重循环。

    代码:

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 110;
    LL w[N];
    
    int main() {
        int t, n;
        cin >> t;
        while (t--) {
            LL sum = 0;
            cin >> n;
            for (int i = 0; i < n; i++) {
                cin >> w[i];
                sum += w[i];
            }
            if (sum % 2 != 0) {
                puts("NO");
                continue;
            }
            sum /= 2;
            sort(w, w + n);
            LL temp = 0;
            for (int i = n - 1; i >= 0; i--) {
                if (temp + w[i] <= sum) {
                    temp += w[i];
                }
            }
            cout << (temp == sum ? "YES" : "NO") << endl; 
        }
    
        return 0;
    }
    
    官方的思路:直接判断,省去循环

    对重量为0的糖果和重量为1的糖果分别统计个数,那么和就是((cnt1 + cnt2 * 2)),若和不能被2整除那肯定为(“NO”),若能被整除,那么分给每个人的重量就为(sum = cfrac{(cnt1 + cnt2*2)}{2}), 再判断糖果是否能实现对两个人的合理分配,若(sum \% 2 == 0),那么说明所给的糖果可以凑出(cfrac{sum}{2})(2)(想不明白可以用反证法:若所给糖果凑不出(cfrac{sum}{2})(2),那么肯定所给糖果中有奇数个(1),那么说明(sum \% 2 != 0),与(sum \% 2 == 0)矛盾)那么就说明可以实现合理分配,如果(sum \% 2 != 0),那么说明在分给一人若干个(2)之后。会有(1)来补齐,因此只需要判断一下(cnt1 != 0)即可。

    #include <iostream>
    
    using namespace std;
    
    int main() {
        int t, n;
        cin >> t;
        while (t--) {
            cin >> n;
            int cnt1 = 0, cnt2 = 0, c;
            for (int i = 0; i < n; i++) {
                cin >> c;
                if (c == 1) {
                    cnt1++;
                } else {
                    cnt2++;
                }
            }        
            if ((cnt1 + cnt2 * 2) % 2 != 0) {
                puts("NO");
            } else {
                int sum = (cnt1 + cnt2 * 2) / 2;
                if ((sum % 2 == 0) || (sum % 2 != 0 && cnt1 != 0)) {
                    puts("YES");
                } else {
                    puts("NO");
                }
            }
        }
    
        return 0;
    }
    

    C. Long Jumps

    链接:C题链接

    题目大意:

    给定一个数组(a),下标是(i in [1, n]),从(i)跳到(i + a[i])的得分是(a[i]),以此类推直到下标超过(n),例如:(n=5),(a=[7,3,1,2,3])
    (i = 1)时,(1 + a[1] = 8),跳出了n,因此(score[1] = a_1 = 7)
    (i = 2)时,(2 + a[2] = 5),跳到了(i = 5),从(5)开始跳,(5 + a[5] = 8),因此(score[2] = a_2 + a_5 = 6)
    依次类推...
    求最后最大(score_i)

    思路

    一开始还是只想到了两重循环暴力,铁定超时,然后就得想怎么才能优化。
    于是发现这样一个递推公式:(score[i] = score[i + a[i]] + a[i]),并且为了记录下(score[i + a[i]]),我们选择倒着枚举,这样(score[i + a[i]])就被提前记录啦,最后再找一下最大值即可,于是就从(O(n^2))优化成了(O(n))

    代码:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    const int N = 2e5 + 10;
    int a[N], f[N];
    
    int main() {
        int t, n;
        cin >> t;
        while (t--) {
            cin >> n;
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
            vector<int> f(n + 1);
            for (int i = n - 1; i >= 0; i--) {
                f[i] = a[i];
                int j = i + a[i];
                if (j < n) {
                    f[i] += f[j];
                }
            }
            cout << *max_element(f.begin(), f.end()) << endl;
        }
        system("pause"); 
        return 0;
    }
    

    D. Even-Odd Game

    链接:D题链接

    题目大意:

    (Alice)(Bob)玩游戏,给定一个数组(a)(Alice)先手,(Bob)后手从里边拿牌,若(Alice)取到的偶数那么就加分加(a_i),否则不加分,(Bob)取到奇数加分,否则不加分,直到牌被取完,最后谁的分数高谁获胜,保证游戏是公平的且两者的取法都是最优。

    思路

    一个简单的博弈论问题,但是我没想出来。
    可以换一种角度思考,取一个基准分,(Alice)取到偶数那么基准分加分,(Bob)取到奇数相当于基准分减分减分,因此这样看来,(Alice)想让它越大越好,(Bob)想让它越小越好。对于(Alice)来说,她肯定想拿的数越大越好,如果是大偶数那么直接加分了,如果是拿大的奇数那么(Bob)就拿不到,因此对于(Bob)也是如此,因此对于两者来说都是拿的分越大越好。
    还有见到一个数(1e9)这种,一定要记得开(long long)

    代码:

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 2E5 + 10;
    ll a[N];
    
    bool cmp(ll a, ll b) {
        return a > b;
    }
    
    int main() {
        int t, n;
        cin >> t;
        while (t--) {
            cin >> n;
            for (int i = 1; i <= n; i++) {
                cin >> a[i];
            }
            ll res = 0;
            sort(a + 1, a + n + 1, cmp);
            for (int  i = 1; i <= n; i++) {
                if (i % 2 == 1) {//Alice取
                    if (a[i] % 2 == 0) {
                        res += a[i];
                    }
                } else { //Bob取
                    if (a[i] % 2 == 1) {
                        res -= a[i];
                    }
                }
            }
            if (res == 0) {
                puts("Tie");
            } else if (res > 0) {
                puts("Alice");
            } else {
                puts("Bob");
            }
        }
    
        return 0;
    }
    

    E. Correct Placement

    链接:E题链接

    题目大意:

    (n)个人拍照,矮的并且瘦得会站在前边,比如有(i)(j)两位同学,(h_i)(w_i)(h_j)(w_j)分别是两位同学的身高,与身体宽度,若((h_j<h_iquad andquad w_j<w_i) quad or quad (h_j<w_i quad andquad w_j<h_i)) 那么(j)同学都可以站在(i)同学的前面,对于每一位同学,输出可以站在它前边的任意一位同学的编号。

    思路

    看博客有个大佬的想法真的太棒了,既然身高体宽都不确定大小,而且都可以用来比较,那么我们再输入的时候直接处理一下,让(h_i)(w_i)较大的那个作为身高即可,这样就不必再处理两遍,按照(h_i)从小到大排一个序列,找到(h_i)不同的情况下,(w)最小的那个(一定是在当前同学的前边找,因为排序过后后边的同学一定是不满足的),并且记录它的坐标,因此贪心一下就始终以(w)最小的作为答案即可,同时若遇到更小的记得更新它,还有就是要注意身高相同的情况下不得更新(min_w)

    代码:

    #include <iostream>
    #include <algorithm>
    #include <tuple>
    
    using namespace std;
    
    const int N = 2e5 + 10;
    int res[N];
    
    struct node {
        int index, h, w;
    } a[N];
    
    bool operator< (const node &a, const node &b) {
        return tie(a.h, a.w, a.index) < tie(b.h, b.w, b.index);
    }
    
    void solve() {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            a[i].index = i;
            cin >> a[i].h >> a[i].w;
            if (a[i].h < a[i].w) {
                swap(a[i].h, a[i].w);
            }
        }
    
        sort(a + 1, a + n + 1);
        int p = 1;
        int min_idx = 0, min_w = 1e9;
        for (int i = 1; i <= n; i++) {
            if (i != 1 && a[i].h != a[i - 1].h) {
                while (p < i) {
                    if (min_w > a[p].w) {
                        min_w = a[p].w;
                        min_idx = a[p].index;
                    }
                    p++;
                }
            }
            if (min_w >= a[i].w) {
                res[a[i].index] = -1;
            } else {
                res[a[i].index] = min_idx;
            }   
        }
        for (int i = 1; i <= n; i++) {
            cout << res[i] << " ";
        }
        cout << endl;
    }
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
    
        return 0;
    }
    
  • 相关阅读:
    tableView的高度问题
    信任机型
    cell 内部 设置width 总不对
    图文混排
    UICollectionview实现自定义cell的移动删除
    ios 各种技术
    打包ane之后在FB上生成ipa的阶段错误
    自动布局出代码植入 的图像化实例
    MapReduce编程实例
    二叉树的遍历(递归遍历、非递归遍历、层序遍历)
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/14292785.html
Copyright © 2011-2022 走看看