Codeforces Global Round 13 A-D题题解

写在前边

链接:Codeforces Global Round 13
\(A,B,C,D\)

A. K-th Largest Value

链接:A题链接

题目大意:

有一个字串只由\(0、1\)组成,有两个操作,\(1\)是让其中\(a_x\)变为\(1-a_x\)\(2\)是询问数组中第\(k\)大的数。

思路

很简单了,字串中元素只在\(0、1\)中变化,要问第\(k\)大的数字,那么非\(1\)\(0\),就用一个\(map\)维护\(0,1\)的数量就好了

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

const int N = 1E5 + 10;
int a[N];

void solve() {
    int n, q;
    scanf("%d%d", &n, &q);
    map<int, int> cnt;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        cnt[a[i]]++;
    }
    while (q--) {
        int t, x;
        scanf("%d%d", &t, &x);
        if (t == 1) {
            if (a[x] == 1) {
                a[x] = 0;
                cnt[0]++, cnt[1]--;
            } else {
                a[x] = 1;
                cnt[1]++, cnt[0]--;
            }
        } else if (t == 2) {
            if (cnt[1] >= x) puts("1");
            else puts("0");
        }
    }
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    solve();
    return 0;
}

B. Minimal Cost

链接:B题链接

题目大意:

每行一个箱子,第\(i\)行箱子的坐标为\(a_i\),你的任务就是推箱子,然后把利用最小的花费把开一条路使得你可以从左上角走到右下角。

思路

注意

  1. 每行就一个!
  2. 你可以随便方向的走!
    那么这样就很简单了,只需要在一列箱子中开一个口就好了,然后不断更新答案即可。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

const int N = 110;
int a[N];

void solve() {
    int n, u, v;
    scanf("%d%d%d", &n, &u, &v);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
    int res = 2e9 + 10;
    for (int i = 2; i <= n; i++) {
        if (abs(a[i] - a[i - 1]) > 1) res = 0;
        if (a[i] == a[i - 1]) res = min(res, v + min(v, u));
        if (abs(a[i] - a[i - 1]) == 1) res = min(res, min(v, u));
    }

    printf("%d\n", res);
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int t;
    scanf("%d", &t); 
    while (t--) {
        solve();
    }

    return 0;
}

C. Pekora and Trampoline

链接:C题链接

题目大意:

跳床,有\(n\)个跳床,床的高度为\(s_i\),每在上边跳一次那么\(s_i\)减小\(1\),每次跨越着跳,当前在\(i\)那么一步会跳到\(i + s_i\)去,每次可以从任意一个跳床开始跳,直到跳出所有跳床算一次操作,那么经过多少次操作,所有的\(s_i\)都变为\(1\),注意已经变为\(1\)的床不会再减小。

思路

贪心的想,假如我们要是所有的床都变为\(1\),那么我们每次一定得从最左边跳到最右边,所以不如直接贪心加模拟的方法解题。

1.维护一个\(p\)数组,\(p_i\)表示已经在第\(i\)张床上跳了\(p_i\)次。
2.更新答案\(res += max(0, s[i] - p[i] - 1)\),即如果\(s[i] - 1 > p[i]\)说明还需要在第i张床上跳\(s[i] - p[i] - 1\)次,如果\(s[i] - 1 \leq p[i]\),那么说明第\(i\)张床上\(s[i]\)已经变为\(1\)。同时如果在第i张床上跳,因为\(s[i]\)每次减一,直到减法为\(1\)(\(s[i] = 1\)就没必要跳了),那么会影响后边第\(i + s[i], ...,i + 2\)床。
3. 还有就是,如果第\(i\)张床上跳的过多,即\(s[i]\)已经变为\(1\)了,那么第\(i\)张床上多余的跳跃次数可以转移到下一张床上。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}

const int N = 5010;
int s[N];
int p[N];

void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &s[i]);

    LL res = 0;
    memset(p, 0, sizeof p);
    for (int i = 1; i <= n; i++) {
        int x = max(0, s[i] - p[i] - 1); 
        res += x;
        for (int j = i + 2; j <= min(n, i + s[i]); j++) {
            p[j]++;
        }
        p[i + 1] += max(p[i] - s[i] + 1, 0);
    }
    printf("%lld\n", res);
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int t;
    scanf("%d", &t); 
    while (t--) {
        solve();
    }
    return 0;
} 

D. Zookeeper and The Infinite Zoo

链接:D题链接

题目大意:

可以在结点\(u\)\(u+v\)连一条边,当前仅当\(u \, \& \, v = v\)的时候,然后给定\(q\)个询问,每次两个端点\(u_i\), \(v_i\)问是否能从\(u_i\)\(v_i\)

思路

首先发现两个性质:

  1. 假如现结点为\(v\),那么它一定可以转移到\(2 * v\),很显然。
  2. 还有就是要满足\(u \, \& \, v = v\),那么起码满足\(u \leq v\),否则直接\(pass\)掉即可

然后再推到发现,\(u\)\(1\)的个数必须要大于等于\(v\)\(1\)的个数,为什么呢?
我们令\(k = v - u\).
我们发现,因为\(u \, \& \, k = k\),那么说明,\(u\)\(k\)的二进制数中存在\(1\)的位数一定在同一位啊,否则不可能按位与得到\(k\),然后实现\(u\)转移到\(u+k = v\),那么\(v\)相对于\(u\)来说肯定是\(u\)其中的某些\(1\)进位才得到了\(u+k = v\),那么所以说\(v\)\(1\)得个数肯定是小于等于\(u\)\(1\)得个数的,举两个例子:
\(u_(2) = 011\), \(k_(2) = 001\),那么\(v_(2) = 100\)\(1\)的个数减少了。
\(u_(2) = 011\), \(k_(2) = 011\),那么\(v_(2) = 110\)\(1\)的个数不变。
那么单纯满足这个条件就对了吗,当然不是。
还要满足,\(v\)中的每一位\(1\)要高于\(u\)中每一位的\(1\),总不能越转移越低吧。那么满足这两个条件,\(u\)\(v\)就可以进行转移了,那么上边的操作都可以用\(lowbit\)运算就可以了

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>

//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define P2LL pair<long long, long long>
#define endl '\n'
#define pub push_back
#define pob pop_back

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int Mod = 10000007;

int lowbit(int x) {
    return x & (-x);
}

void solve() {
    int u, v;
    scanf("%d%d", &u, &v);
    
    if (u > v) {
        puts("NO");
        return;
    }
    int uu = u, vv = v;
    int cnt1 = 0, cnt2 = 0;
    while (uu) { //u中1的个数
        uu -= lowbit(uu);
        cnt1++;
    }
    while (vv) { //v中1的个数
        vv -= lowbit(vv);
        cnt2++;
    }
    while (u && v) { //必须往高位推才行
        if (lowbit(u) > lowbit(v)) {
            puts("NO");
            return;
        }
        u -= lowbit(u), v -= lowbit(v); 
    }
    if (cnt1 >= cnt2) puts("YES");
    else puts("NO");
}

int main()
{
    //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int t;
    scanf("%d", &t); 
    while (t--) {
        solve();
    }

    return 0;
}
posted @ 2021-03-05 18:16  Xxaj5  阅读(82)  评论(0编辑  收藏  举报