Codeforces Round #593 (Div. 2)

A
暴力计算

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
 
int main()
{
    int t; cin >> t;
    while (t--) {
        int a, b, c; cin >> a >> b >> c;
        int ans = 0;
        ans += 3 * min(c / 2, b);
        ans += 3 * min(a, (b - min(c / 2, b)) / 2);
        cout << ans << endl;
    }
}

B
把每个物品分到m个盒子的全部可能性 -空(2^m-1),n个盒子即^n

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int mod = 1e9 + 7;
typedef long long ll;
ll qpow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}
 
int main()
{
    int n, m; cin >> n >> m;
    cout << qpow((qpow(2, m) - 1 + mod) % mod, n) << endl;
}

C
分析样例
n组,每次按照奇数组id+1,偶数组id-1分配

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 300 + 5;
int ans[maxn];
int main()
{
    int n; cin >> n;
    for (int i = 1; i <= n; ++i) {
        if (i & 1) ans[i] = n * (i - 1) + 1;
        else ans[i] = n * i;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (j > 1) putchar(' ');
            printf("%d", ans[j]);
            if (j & 1) ans[j]++;
            else ans[j]--;
        }
        putchar('\n');
    }
}

D
分析机器人运行,发现即是机器人朝一个方向走遇到障碍物即要转弯
模拟机器人运行即可,注意每一行每一列只会走一次,直接排序障碍物,找出路径上与出发点前进方向上最近的点

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
vector<int> line[maxn], col[maxn];
bool less_cmp(int a, int b) { return a > b; }
struct Tre {
    int a[3][maxn << 2];
    void build(int rt, int l, int r) {
        if (l == r) {
            a[0][rt] = inf; a[1][rt] = -1;
            return;
        }
        int mid = (l + r) >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
        a[0][rt] = min(a[0][rt << 1], a[0][rt << 1 | 1]);
        a[1][rt] = max(a[1][rt << 1], a[1][rt << 1 | 1]);
    }
    void update(int rt, int l, int r, int pos) {
        if (l == r) {
            a[0][rt] = a[1][rt] = pos;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) update(rt << 1, l, mid, pos);
        else update(rt << 1 | 1, mid + 1, r, pos);
        a[0][rt] = min(a[0][rt << 1], a[0][rt << 1 | 1]);
        a[1][rt] = max(a[1][rt << 1], a[1][rt << 1 | 1]);
    }
    int queryMin(int rt, int l, int r, int L, int R) {
        if (L <= l && r <= R) return a[0][rt];
        int mid = (l + r) >> 1, res = inf;
        if (L <= mid) res = min(res, queryMin(rt << 1, l, mid, L, R));
        if (mid < R) res = min(res, queryMin(rt << 1 | 1, mid + 1, r, L, R));
        return res;
    }
    int queryMax(int rt, int l, int r, int L, int R) {
        if (L <= l && r <= R) return a[1][rt];
        int mid = (l + r) >> 1, res = -1;
        if (L <= mid) res = max(res, queryMax(rt << 1, l, mid, L, R));
        if (mid < R) res = max(res, queryMax(rt << 1 | 1, mid + 1, r, L, R));
        return res;
    }
} usedline, usedcol;
map<pair<int, int>, bool> check;
int main()
{
    int n, m, k; scanf("%d%d%d", &n, &m, &k);
    ll realk = 0;
    for (int i = 1; i <= k; ++i) {
        int x, y; scanf("%d%d", &x, &y);
        if (check.count(make_pair(x, y))) continue;
        realk++;
        line[x].push_back(y);
        col[y].push_back(x);
    }
    for (int i = 1; i <= n; ++i) line[i].push_back(0), line[i].push_back(m + 1);
    for (int i = 1; i <= m; ++i) col[i].push_back(0), col[i].push_back(n + 1);
    usedline.build(1, 0, n + 1); usedcol.build(1, 0, m + 1);
    usedline.update(1, 0, n + 1, 0), usedline.update(1, 0, n + 1, n + 1);
    usedcol.update(1, 0, m + 1, 0), usedcol.update(1, 0, m + 1, m + 1);
    ll ans = 1;
    int x = 1, y = 1, p = 0, flg = 1;
    while (true) {
        //cout << x << ", " << y << " : " << p << endl;
        if (p == 0) {
            sort(line[x].begin(), line[x].end());
            int ret = *lower_bound(line[x].begin(), line[x].end(), y);
            ret = min(ret, usedcol.queryMin(1, 0, m + 1, y + 1, m + 1));
            //cout << ret << endl;
            if (ret == y) break;
            if (ret == y + 1) {
                if (flg) { flg = 0; p = (p + 1) % 4; continue; }
                else break;
            }
            usedline.update(1, 0, n + 1, x);
            ans += ret - y - 1;
            y = ret - 1; p = (p + 1) % 4;
            if (flg) flg = 0;
        }
        else if (p == 1) {
            sort(col[y].begin(), col[y].end());
            int ret = *lower_bound(col[y].begin(), col[y].end(), x);
            ret = min(ret, usedline.queryMin(1, 0, n + 1, x + 1, n + 1));
            //cout << ret << endl;
            if (ret == x || ret == x + 1) break;
            usedcol.update(1, 0, m + 1, y);
            ans += ret - x - 1;
            x = ret - 1; p = (p + 1) % 4;
        }
        else if (p == 2) {
            sort(line[x].begin(), line[x].end(), less_cmp);
            int ret = *lower_bound(line[x].begin(), line[x].end(), y, less_cmp);
            ret = max(ret, usedcol.queryMax(1, 0, m + 1, 0, y - 1));
            //cout << ret << endl;
            if (ret == y || ret == y - 1) break;
            usedline.update(1, 0, n + 1, x);
            ans += y - ret - 1;
            y = ret + 1; p = (p + 1) % 4;
        }
        else {
            sort(col[y].begin(), col[y].end(), less_cmp);
            int ret = *lower_bound(col[y].begin(), col[y].end(), x, less_cmp);
            ret = max(ret, usedline.queryMax(1, 0, n + 1, 0, x - 1));
            //cout << ret << endl;
            if (ret == x || ret == x - 1) break;
            usedcol.update(1, 0, m + 1, y);
            ans += x - ret - 1;
            x = ret + 1; p = (p + 1) % 4;
        }
    }
    cout << ((ans == 1ll * n * m - realk) ? "Yes" : "No") << endl;
}

E
我们需要计算(i,j)对数,枚举i,我们发现能到的最大的j和最小的j之间都能到达。把问题抽象为二维平面不经过障碍点,每次能向上或向下或向右能到达的最高点和最低点。
没有障碍点时会一直走斜线,按斜线保存x坐标,每次二分大于等于改点的斜线上的点,走到它的下面。
https://www.cnblogs.com/heyuhhh/p/11698762.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值