Codeforces Round #791 (Div. 2)(A-D)

Codeforces Round #791 (Div. 2)(A-D)

A. AvtoBus

题意:

给你 n, 问满足 4 x + 6 y = n 4x+6y=n 4x+6y=n x + y x+y x+y的最小值和最大值是多少? x , y x,y x,y 都是非负整数。

题解:

n如果是奇数,无解。如果是偶数,等式除以2,考虑 2 x + 3 y = n 2x+3y=n 2x+3y=n

要想使得 x + y x+y x+y尽可能大,那么x要尽量多,就需要找最小的y满足 n − 3 y n-3y n3y是偶数,分别讨论摸3的各种情况。反之同理。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);
    int t;
    ll n;

    cin >> t;
    while (t--) {
        cin >> n;
        if (n & 1 || n == 2) {
            cout << -1 << endl;
            continue;
        }

        n /= 2;

        ll mi = 1e9, mx = 0;

        if (n < 4) {
            cout << "1 1" << endl;
            continue;
        }

        switch (n % 3) {
        case 0:
            mi = n / 3;
            break;
        case 1:
            mi = (n - 4) / 3 + 2;
            break;
        case 2:
            mi = (n - 2) / 3 + 1;
            break;
        default:
            break;
        }

        if (n & 1) {
            mx = max(mi, 1 + (n - 3) / 2);
        }
        else {
            mx = max(mi, n / 2);
        }


        cout << mi << ' ' << mx << endl;
    }
    return 0;
}

B. Stone Age Problem

题意:

给你 长度为 n n n的数组 a a a, 有两种操作:

  1. a i a_i ai改成 x x x
  2. 把所有数改成 x x x

输出每次操作后

题解:

单点更新,区间更新,维护区间和,这不就是线段树吗,练板子了。。。。当然,这里是区间赋值

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;


int n, q, a[MAXN];

struct node {
    int l, r;
    ll lazy;
    ll sum;
} tr[MAXN << 2];

inline int lson(int x) {
    return x << 1;
}
inline int rson(int x) {
    return x << 1 | 1;
}

void pushup(int x) {
    tr[x].sum = tr[lson(x)].sum + tr[rson(x)].sum;
}

void pushdown(int x) {
    if (tr[x].lazy) {
        tr[lson(x)].lazy = tr[x].lazy;
        tr[rson(x)].lazy = tr[x].lazy;
        tr[lson(x)].sum = (tr[lson(x)].r - tr[lson(x)].l + 1) * tr[x].lazy;
        tr[rson(x)].sum = (tr[rson(x)].r - tr[rson(x)].l + 1) * tr[x].lazy;
        tr[x].lazy = 0;
    }
}

void build(int x, int l, int r) {
    tr[x].l = l, tr[x].r = r, tr[x].lazy = 0;
    if (l == r) {
        return;
    }

    int mid = l + r >> 1;
    build(lson(x), l, mid);
    build(rson(x), mid + 1, r);
    pushup(x);
}

ll query(int x, int l, int r) {
    if (tr[x].l >= l && tr[x].r <= r)
        return tr[x].sum;

    if (tr[x].l > r || tr[x].r < l)
        return 0;

    pushdown(x);
    return query(lson(x), l, r) + query(rson(x), l, r);
}

void update(int x, int l, int r, ll k) {
    if (tr[x].l >= l && tr[x].r <= r) {
        tr[x].lazy = k;
        tr[x].sum = (tr[x].r - tr[x].l + 1) * k;
        return;
    }

    if (tr[x].l > r || tr[x].r < l)
        return;

    pushdown(x);
    update(lson(x), l, r, k);
    update(rson(x), l, r, k);
    pushup(x);
}


int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> q;
    build(1, 1, n);

    for (int i = 1; i <= n; i++) {
        int a;
        cin >> a;
        update(1, i, i, a);
    }

    while (q--) {
        int t, x, i;
        cin >> t;
        if (t == 1) {
            cin >> i >> x;
            update(1, i, i, x);
        }
        else {
            cin >> x;
            update(1, 1, n, x);
        }
        cout << query(1, 1, n) << endl;
    }
    return 0;
}

C. Rooks Defenders

题意:

给你 n*n的国际象棋棋盘,有3种操作:

  1. ( i , j ) (i,j) (i,j)处放一个车
  2. 移除 ( i , j ) (i,j) (i,j)处的车
  3. 查询矩形 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1), (x_2,y_2) (x1,y1),(x2,y2)的所有点是不是都被车攻击到
题解:

用两个树状数组维护行和列能不能被车吃到,放子的时候,注意幂等,也就是说,这一行/列如果已经被车吃到了,就不用放了。

也可以用线段树做,维护区间最小值。

#include <bits/stdc++.h>

using namespace std;

#define int long long

typedef pair<int, int> pii;

const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;

int n, q;

int tr1[MAXN], tr2[MAXN];
int r[MAXN], c[MAXN];
inline int lowbit(int x) {
    return x & (-x);
}

void add(int* tr, int i, int d) {
    while (i <= n) {
        tr[i] += d;
        i += lowbit(i);
    }
}

int sum(int* tr, int i) {
    int res = 0;
    while (i > 0) {
        res += tr[i];
        i -= lowbit(i);
    }
    return res;
}


signed main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);
    int t;
    int x, y, x1, x2, y1, y2;

    cin >> n >> q;
    while (q--) {
        cin >> t;
        if (t == 1) {
            cin >> x >> y;
            r[x]++, c[y]++;
            if (r[x] == 1) add(tr1, x, 1);
            if (c[y] == 1) add(tr2, y, 1);
        }
        else if (t == 2) {
            cin >> x >> y;
            r[x]--, c[y]--;
            if (r[x] == 0) add(tr1, x, -1);
            if (c[y] == 0) add(tr2, y, -1);
        }
        else {
            cin >> x1 >> y1 >> x2 >> y2;

            bool row = sum(tr1, x2) - sum(tr1, x1 - 1) >= x2 - x1 + 1;
            bool col = sum(tr2, y2) - sum(tr2, y1 - 1) >= y2 - y1 + 1;

            puts((row || col) ? "Yes" : "No");
        }
    }
    return 0;
}

D.Toss a Coin to Your Graph…

题意:

给你一个图,选择一条长度为 k − 1 k-1 k1的路径,使得沿路k个点的点权的最大值最小

题解:

看到最X值最X,刻在DNA里就是“二分答案“,那么我们可以看出答案最大值为点权最大值1e9,最小值为0,二分答案记为mid,则问题转化为:

是否存在一条长度为 k − 1 k-1 k1 的路径,使得沿路k个点的点权不超过 m i d mid mid ?

可以想到,如果存在,那么这条路径经过的点的点权都不超过mid,那就一定在原图里面点权小于mid的子图里面,则问题可以进一步转化为:

给你一个图,是否存在长度为 k − 1 k-1 k1的路径?

这样问题就变得容易解决了,首先如果有环,一定存在任意长度的路径。

否则是个dag图,拓扑排序的时候记录dp[i]表示从入度为0的点走到i点的最长路径,如果走到了k,则直接返回true,否则拓扑排序出来之后判断是否仍有入度不为0的点,如果有,说明一定存在环,若存在环,就说明任意长度的路径都存在,返回true,否则为false。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;

int n, m;
ll k;
ll a[MAXN];

vector<int> g[MAXN];

int in[MAXN];
bool vis[MAXN];
int dp[MAXN];
// 建一个新图
vector<int> g2[MAXN];
unordered_set<int> s;


// if exists path which max number of it <= x
bool check(int x) {
    s.clear();
    for (int i = 1; i <= n; i++) {
        in[i] = vis[i] = dp[i] = 0;
        g2[i].clear();
        if (a[i] <= x) s.insert(i), dp[i] = 1;
    }
    for (int i = 1; i <= n; i++) {
        for (auto j : g[i]) {
            if (s.find(i) != s.end() && s.find(j) != s.end()) {
                g2[i].push_back(j);
                in[j]++;
            }
        }
    }


    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (s.find(i) != s.end() && !in[i]) q.push(i);
    }

    while (!q.empty()) {
        int j = q.front();
        q.pop();
        vis[j] = true;

        if (dp[j] >= k) return true;
        for (auto u : g2[j]) {
            if (!vis[u]) {
                dp[u] = max(dp[u], dp[j] + 1);
                if (dp[u] >= k) return true;
                in[u]--;
                if (!in[u]) q.push(u);
            }
        }
    }

    for (int i = 1; i <= n; i++) {
        if (s.find(i) != s.end() && in[i]) return true;
    }
    return false;
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
    }

    ll l = 0, r = 1e9;
    while (l < r) {
        ll mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }

    // cout << l << endl;
    if (check(l))cout << l << endl;
    else cout << -1 << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值