AtCoder Beginner Contest 157 solution to a problem report

A:Duplex Printing

Subject to the effect:

给你一个数,一次能打印两面,问表示需要打印多少张才能将所有打印完。

Xitidekan:

如果这个数是偶数, 需要打印 n / 2
如果这个数是奇数, 需要打印 n / 2 + 1.

Inspection points:

签到,思维

Code:

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

#define INF 0x3f3f3f3f

using namespace std;

typedef long long LL;
typedef pair<int,int>PII; 

int main(void) {
    int n;
    cin >> n;
    if(n & 1) cout << n / 2 + 1 << endl;
    else cout << n / 2 << endl;
    return 0;
}

B:Bingo

Subject to the effect:

给一个 3 * 3 的矩阵,每个位置有一个数,之后再给你一些数,如果这些数在这个矩阵中
并且所以数组合到一起可以使得 有一列或者有一行或者斜对角 都出现过,就输出 Yes,
否则输出 No.

Xitidekan:

没有想到好的方法,就一个一个枚举了,hh,方法虽然笨点,总归是 AC 了。

Inspection points:

模拟

Code :

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

#define INF 0x3f3f3f3f

using namespace std;

typedef long long LL;
typedef pair<int,int>PII; 

int a[5][5];
int cnt[5][5];

int main(void) {
    for(int i = 1; i <= 3; i ++) {
        for(int j = 1; j <= 3; j ++) {
            cin >> a[i][j];
        }
    }
    int n,value;
    cin >> n;
    while(n --) {
        cin >> value;
        bool vis = false;
        for(int i = 1; i <= 3; i ++) {
            for(int j = 1; j <= 3; j ++) {
                if(a[i][j] == value) {
                    vis = true;
                    cnt[i][j] = 1;
                    break;
                }
            }
            if(vis) break;
        }
    }
    if((cnt[1][1] == 1 && cnt[1][2] == 1 && cnt[1][3] == 1) || (cnt[2][1] == 1 && cnt[2][2] == 1 && cnt[2][3] == 1) ||
        (cnt[3][1] == 1 && cnt[3][2] == 1 && cnt[3][3] == 1) || (cnt[1][1] == 1 && cnt[2][1] == 1 && cnt[3][1] == 1) ||
        (cnt[1][2] == 1 && cnt[2][2] == 1 && cnt[3][2] == 1) || (cnt[1][3] == 1 && cnt[2][3] == 1 && cnt[3][3] == 1) ||
        (cnt[1][1] == 1 && cnt[2][2] == 1 && cnt[3][3] == 1) || (cnt[1][3] == 1 && cnt[2][2] == 1 && cnt[1][3] == 1)
    ) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    return 0;
}

C:Guess The Number

Subject to the effect:

大概就是说给你一个不超过三位的一个数,然后这之后会有一些操作,可以指定某一位是多少,
但是不允许有前导 0 ,同一个位置不能重复指定,否则会出现错误,除了指定的数外,还要保证
最后得到的数是最小的。

Xitidekan:

题是不难,就是细节忒多,需要考虑的情况比较多,这道题我还犯了一个小错误,就是重复输出了,
对于某一种情况没有及时跳出来,导致对某一个测试样例会输出两个答案。不过这道题收获还是
蛮多的,重要的是学会尝试着去找不同的情况去接近答案。

Inspection points:

思维,模拟

Code:

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

#define INF 0x3f3f3f3f

using namespace std;

typedef long long LL;
typedef pair<int,int>PII;

int n,m;

int x,b;

int a[4],cnt[4];

int main(void) {
    cin >> n >> m;
    if(n == 1 && m == 0) {
        // 这种情况要及时跳出来,不然就与下面的冲突了 
        cout << 0 << endl;
        return 0;
    }
    bool vis = true;
    while(m --) {
        cin >> x >> b;
        if(vis == false) continue;
        if(n > 1 && x == 1 && b == 0) {
            vis = false;
        } else if(cnt[x] && a[x] != b) {
            vis = false;
        } else {
            a[x] = b;
            cnt[x] = 1;
        }
    }
    if(vis == false) {
        cout << -1 << endl;
    } else {
        for(int i = 1; i <= n; i ++) {
            if(a[1] == 0 && cnt[1] == 0) a[1] = 1;
            cout << a[i] ;
        }
        cout << endl;
    }
    return 0;
}

D:Friend Suggestions

Subject to the effect:

先给一些关系,表明两个数之间是朋友的关系,接着再给一些关系,表示这些人之间不是朋友的
关系,最后问你每个人可以有多少个人可以是自己的候选朋友(不包括已有的),而且所有人跟
自己还必须是在同一个连通块内的。

Xitidekan:

这题是赛后补的,琢磨完第三题剩下的时间就不多了,跟一些大佬真的没法比,不过最后靠自己
的能力把这道题补出来,自己还是很欣慰的。
一看到这道题涉及到关系,第一时间想到的就是并查集,然后就往哪里想,实际上是带权并查集
的初级版,我们最后求得是候选的朋友,我们可以求出这个连通块的大小,然后每个人的朋友就是
当前这个点的出度,还有在同一个连通块中跟这个人也有可能不是朋友,这是我们可以拿一个
cnt 数组用来计算不是朋友的数量(是双向的,具体的会在代码中体现),然后这个连通块的大小
- 朋友数量 - 不是朋友的数量 = 候选朋友的数量(同一个连通块内)。

Inspection points:

带权并查集,连通块

Code:

#include <map>
#include <set>
#include <queue>
#include <deque>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

#define INF 0x3f3f3f3f

using namespace std;

typedef long long LL;
typedef pair<int,int>PII;

const int maxn = 1e5 + 10;

int vis[maxn],cnt[maxn];
int fa[maxn],sz[maxn],deg[maxn];

int ans = 0;

int get(int x) {
    return x == fa[x] ? x : fa[x] = get(fa[x]);
}

void Union(int x,int y) {
    int xx = get(x);
    int yy = get(y);
    if(xx == yy) return ;
    fa[yy] = xx;
    sz[xx] += sz[yy];
    return ;
}

int main(void) {
    int n,m,k;
    int u,v;
    cin >> n >> m >> k;
    for(int i = 1; i <= n; i ++) {
        fa[i] = i;
        // 刚开始每个都是独立的,都是一个 
        sz[i] = 1;

    }
    for(int i = 1; i <= m; i ++) {
        cin >> u >> v;
        // 记录每个点的出度 
        deg[u] ++;
        deg[v] ++;
        Union(u,v);
    }
    for(int i = 1; i <= k; i ++) {
        cin >> u >> v;
        if(get(u) == get(v)) {
            // 不是朋友,但在同一个连通块内,所以都需要减少 
            cnt[u] --;
            cnt[v] --;
        }
    }
    for(int i = 1; i <= n; i ++) {
        cout << sz[get(i)] - deg[i] + cnt[i] - 1<< " ";
    }
    return 0;
}

E:Simple String Queries

Subject to the effect:

有一串字符,我们可以执行两种操作:
1、替换某个位置的字符
2、查询某一段区间不同字符的个数

Xitidekan:

很明显:这道题的两种操作分别是:单点修改,区间查询
是不是跟树状数组的基本操作十分的类似,当然,线段树也是可以的,但是杀鸡焉用牛刀,
关键是自己太菜,哈哈。我们可以用一个二维的数组记录当前位置之前每个字符出现的数量。
具体实现看代码。

Inspection points:

树状数组,线段树

Code:

#include <cstdio> 
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 5e5 + 10;

char a[maxn];

int c[maxn][26];

int t,op,pos,l,r,len;
char v;

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

void insert(int id,int x,int v) {
    for(int i = id; i <= len; i += lowbit(i)) {
        c[i][x] += v;
    }
    return ;
}

int query(int id,int x) {
    int ans = 0;
    // x 代表是( x - 'a') 
    for(int i = id; i; i -= lowbit(i)) {
        ans += c[i][x];
    }
    return ans;
}

int main(void) {
    cin >> len;
    scanf("%s",a + 1);
    for(int i = 1; i <= len; i ++) {
        int v = a[i] - 'a';
        insert(i,v,1);
    }
    cin >> t;
    while(t --) {
        cin >> op; 
        if(op == 1) {
            cin >> pos >> v;
            // 更新 
            insert(pos,a[pos] - 'a',-1);
            insert(pos,v - 'a',1);
            a[pos] = v;                    // 修改后记得修改原数组 
        } else {
            cin >> l >> r;
            int res = 0;
            for(int i = 0; i < 26; i ++) {
                // 如果这个区间有这个字符,只需要 + 一次即可 
                if(query(r,i) - query(l - 1,i)) res ++;
            }
            cout << res << endl;
        }
    }
    return 0;
}

F:Yakiniku Optimization Problem

待补

postscript:

本人能力有限,写的不当之处还望各位看官多多指教,如在参考中遇到各种问题,欢迎大家
留言交流,共同交流。

Guess you like

Origin www.cnblogs.com/prjruckyone/p/12398635.html