Codeforces Round #693 (Div. 3) A~E 题解

写在前边

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

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

A. Cards for Friends

链接:A题链接

题目大意:

给定一张wh的卡片,每次可以切成w2h或者h2w的两张卡片,给定一个整数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+cnt22),若和不能被2整除那肯定为NO,若能被整除,那么分给每个人的重量就为sum=(cnt1+cnt22)2, 再判断糖果是否能实现对两个人的合理分配,若sum%2==0,那么说明所给的糖果可以凑出sum22(想不明白可以用反证法:若所给糖果凑不出sum22,那么肯定所给糖果中有奇数个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[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]=a1=7
i=2时,2+a[2]=5,跳到了i=5,从5开始跳,5+a[5]=8,因此score[2]=a2+a5=6
依次类推...
求最后最大scorei

思路

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

题目大意:

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

思路

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

代码:

#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个人拍照,矮的并且瘦得会站在前边,比如有ij两位同学,hiwihjwj分别是两位同学的身高,与身体宽度,若(hj<hiandwj<wi)or(hj<wiandwj<hi) 那么j同学都可以站在i同学的前面,对于每一位同学,输出可以站在它前边的任意一位同学的编号。

思路

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

代码:

#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;
}
posted @   Xxaj5  阅读(118)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示