Codeforces Round #693 (Div. 3) 题解 除G题

看不懂G题啥意思,寄!

A - Cards for Friends

如果长或宽任意一个为偶数,意味着可以得到当前拥有的Card数的2倍

from math import *
from collections import *
N = int(1e9 + 7)

def read():
    return list(map(int, input().strip().split(' ')))

# start
n2, = read()
for _ in range(n2):
    w, h, n = read()
    piece = 1 # 当前有piece片Card
    flag = 0 # 能否成功给所有人送出Card
    while True:
        if piece >= n:
            flag = True
            break
        
        if w & 1 == 0:
            w //= 2
            piece *= 2
        elif h & 1 == 0:
            h //= 2
            piece *= 2
        else:
            break
    if flag:
        print('yes')
    else:
        print('no')

B - Fair Division

根据两种糖果的数量的奇偶性进行判断即可
具体看注释

from math import *
from collections import *
N = int(1e9 + 7)

def read():
    return list(map(int, input().strip().split(' ')))

def check(dic):
    x, y, s = dic[1] % 2, dic[2] % 2, (dic[1] + dic[2] * 2) % 2
    # 总和为奇数,不可能分配成功
    if s == 1:
        return False
    # 下面是总和为偶数时,这时1克重的糖肯定有偶数个
    # 2克重的糖有偶数个时,肯定能对半分完
    if y == 0:
        return True
    # 2克重的糖有奇数个时
    elif y == 1:
    	# 没有1克重的糖时,分配完会多出一个2克糖
        if dic[1] == 0: return False
        # 假设A拿了2颗2g的糖,B拿了3颗2g的糖
      	# 此时有2颗以上的1g的糖,再给A 2颗1g的糖。剩下的1g的糖平均分配就行
        return True


# start
n2, = read()
for _ in range(n2):
    n, = read()
    a = read()
    dic = Counter(a)
    print('yes' if check(dic) else 'no')

C - Long Jumps

记忆化搜索
在这里插入图片描述
可以从图中看出,如果暴力来做,有重复的地方。
那么我们不妨记录一下从每个点出发所得的分;如果计算过了,那么就不用往下走了。

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define _rp(i, a, b) for (int i = a; i < b; i++)
int n, a[205000], dp[205000];
int dpp(int i) {
    if (i > n) return 0;
    if (dp[i] != -1)
        return dp[i];
    else {
        dp[i] = dfs(i + a[i]) + a[i];
        return dp[i];
    }
}
int main() {
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    // freopen("code.txt", "r", stdin);
    int _;
    cin >> _;
    while (_--) {
        int ans = -1;
        cin >> n;
        _rp(i, 1, n + 1) {
            cin >> a[i];
            dp[i] = -1;
        }
        _rp(i, 1, n + 1) { ans = max(ans, dpp(i)); }
        cout << ans << endl;
    }
    return 0;
}

D - Even-Odd Game

不管怎么样,他们两个人都要去拿当前最大的数。
拿Alice举例,如果当前最大的数是偶数,那她肯定要拿,同时加分。 如果是奇数,她拿了虽然不加分,但是对面也拿不到这个大分,经典损人利己法。
最后看一下谁的分多就行

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define _rp(i, a, b) for (int i = a; i < b; i++)
ll n, a[205000];

int main() {
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    // freopen("code.txt", "r", stdin);
    int _;
    cin >> _;
    while (_--) {
        ll ans = 0;
        cin >> n;
        _rp(i, 0, n) { cin >> a[i]; }
        sort(a, a + n, greater<int>());
    
        _rp(i, 0, n) {
            // Alice
            if (i % 2 == 0 && a[i] % 2 == 0) ans += a[i];
            // Bob
            if (i % 2 == 1 && a[i] % 2 == 1) ans -= a[i];
            // cout << ans << endl;
        }
        if (ans > 0)
            cout << "Alice" << endl;
        else if (ans == 0)
            cout << "Tie" << endl;
        else
            cout << "Bob" << endl;
    }
    return 0;
}

E - Correct Placement

这题挺有意思的
因为一个人可以躺着或站着,那么我们不妨令 w = m i n ( w , h ) , h = m a x ( w , h ) w=min(w,h),h=max(w,h) w=min(w,h),h=max(w,h),方便处理。(注意不要先让 w = m i n ( w , h ) w=min(w,h) w=min(w,h),此时的w可能会发生变化)
然后使用一个map(mp)记录所有 w w w对应的 h h h及id
此时,拥有最小的 w w w的人的前面肯定无法站人(要满足严格小于才行)。直接记录他们的前面站的人的 i d id id为-1。
用min_h记录当前最小的 h h h,min_h_id 记录id

// 如果这个人拥有最小的w,那么他前面一定无法站任何人,记为-1
for (auto [h, id] : mp.begin()->second) {
    d[id] = -1;
    // 记录当前最小的h的id(id可能有多个,不过无所谓的,题目说任意)
    if (h < min_h) {
        min_h = h;
        min_h_id = id;
    }
}

然后开始按 w w w从小到大的顺序对这些人遍历
对于 w = w i w=w_i w=wi的人,如果他的 h h h大于当前min_h,那么说明有某个人的 w j < w i 且 h j < h i w_j<w_i且h_j<h_i wj<wihj<hi,那么我们就让这个人站在他前面。(min_h对应的 w w w一定是小于 w i w_i wi

if (h > min_h) {
    d[id] = min_h_id;
}
// 如果连最小的h都比不过,就没必要和其他更大的h进行比较了,此时前面不能站人
else {
    d[id] = -1;
}

再次对 w = w i w=w_i w=wi的人遍历他们的 h h h,此时更新min_h。这时候我们就可以保证——在下一次遍历中,min_h所对应的 w j w_j wj一定小于下一次遍历的 w i w_i wi,满足严格 w j w_j wj小于 w i w_i wi的条件

// 再次遍历,看当前w中是否有更小的h为我们所用
// 在下一次遍历中,最小的h所对应的w一定小于下一次遍历的w,满足严格wj小于的条件wi
for (auto [h, id] : it->second) {
    if (h < min_h) {
        min_h = h;
        min_h_id = id;
    }
}

最后输出一下答案就行,其实这题用排序也行。。

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define _rp(i, a, b) for (int i = a; i < b; i++)
ll n;
int d[205000];
int main() {
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    // freopen("code.txt", "r", stdin);
    int _;
    cin >> _;
    while (_--) {
        cin >> n;
        map<int, list<pair<int, int>>> mp;  // 记录所有w对应的h及id
        _rp(i, 0, n) {
            int w, h;
            cin >> w >> h;
            mp[min(w, h)].push_back({max(w, h), i + 1});
        }
        int min_h = 1000000009, min_h_id;
        // 如果这个人拥有最小的w,那么他前面一定无法站任何人,记为-1
        for (auto [h, id] : mp.begin()->second) {
            d[id] = -1;
            // 记录当前最小的h的id(id可能有多个,不过无所谓的,题目说任意)
            if (h < min_h) {
                min_h = h;
                min_h_id = id;
            }
        }
        mp.erase(mp.begin());  //处理过了,删掉
        // 对w从小到大的顺序进行遍历
        for (auto it = mp.begin(); it != mp.end(); it++) {
           // cout << "min_h:"<<min_h<<endl;
            for (auto [h, id] : it->second) {
                // cout << "h:"<<h<<endl;
                // 如果此时的h大过最小的h,同时肯定满足 此时的h 大过
                // 最小的h的w(因为我们是对w从小到大遍历的) 那么当前的人前面可以站一个人
                if (h > min_h) {
                    d[id] = min_h_id;
                }
                // 如果连最小的h都比不过,就没必要和其他更大的h进行比较了,此时前面不能站人
                else {
                    d[id] = -1;
                }
            }
            // 再次遍历,看当前w中是否有更小的h为我们所用
            // 在下一次遍历中,min_h所对应的w_j一定小于下一次遍历的w_i,满足严格w_j小于w_i的条件
            for (auto [h, id] : it->second) {
                if (h < min_h) {
                    min_h = h;
                    min_h_id = id;
                }
            }
        }

        _rp(i, 1, n + 1) { cout << d[i] << ' '; }
        cout << endl;
    }
    return 0;
}

F - Equalize the Array

这里就不拾人牙慧了
和我思路差不多的题解,有图

 
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<int, int> pii;
#define _rp(i, a, b) for (int i = a; i < b; i++)
int n, m;
pii a[205000];
bool check() {
    cin >> n >> m;

    _rp(i, 0, m) { cin >> a[i].second >> a[i].first; }
    // 奇数一定不行
    if (m % 2 == 1) return false;
    // 对列排序
    sort(a, a + m);
    for (int i = 0; i < m - 1; i += 2) {
        int j = i + 1, k = j + 1;
        // 后面还有两个,且在同一列上
        if (k < m && (a[k].first == a[j].first) && (a[k].second != a[j].second)) {
            return false;
        } else {
            // 同列
            if (a[i].first == a[j].first) continue;
            // 间隔数是否为奇数
            int odd = (a[j].first - a[i].first - 1) % 2;
            // 同行
            if (a[i].second == a[j].second) {
                if (odd != 0) return false;
            }
            // 不同行
            else {
                if (odd == 0) return false;
            }
        }
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    // freopen("code.txt", "r", stdin);
    int _;
    cin >> _;
    while (_--) {
        if ((check())) {
            cout << "yes\n";
        } else {
            cout << "no\n";
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值