AtCoder Beginner Contest 157

AtCoder Beginner Contest 157

B

\(and,not,or\) 这些关键字比较好打

这题加个标记数组就好

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int g[N][N],b[N],n;
bool appear[N][N];
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    for(int i = 0;i < 3; ++i)
        for(int j = 0;j < 3; ++j)
            cin >> g[i][j];
    cin >> n;
    for(int i = 0;i < n; ++i) {
        cin >> b[i];
    }
    for(int i = 0;i < 3; ++i) {
        for(int j = 0;j < 3; ++j) {
            for(int k = 0;k < n; ++k) {
                if(b[k] == g[i][j]) appear[i][j] = 1;
            }
        }
    }
    bool f = 0;
    for(int i = 0;i < 3; ++i) {
        if(appear[i][0] and appear[i][1] and appear[i][2]) f = 1;
        if(appear[0][i] and appear[1][i] and appear[2][i]) f = 1;
    }
    if(appear[0][0] and appear[1][1] and appear[2][2]) f = 1;
    if(appear[0][2] and appear[1][1] and appear[2][0]) f = 1;
    if(f) cout << "Yes";
    else cout << "No";

    return 0;
}

C

细节太多,有点坑,一定要多考虑边界情况

n == 1 and m == 0

n == 1 and m == 1

还有首位不能是 0,只能补 1

#include <bits/stdc++.h>
using namespace std;
int a[5];
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n,m,c,s;
    cin >> n >> m;
    memset(a,-1,sizeof a);
    if(n == 1 and m == 0) {
        cout << 0;
        return 0;
    }
    for(int i = 0;i < m; ++i) {
        cin >> c >> s;
        if(a[c] == -1) {
            a[c] = s;
        }
        else if(a[c] != s) {
            cout << "-1";
            return 0;
        }
    }
    if(a[1] == 0 and n > 1) {
        cout << -1;
        return 0;
    }
    if(a[1] == -1) a[1] = 1;
    for(int i = 1;i <= n; ++i) {
        if(a[i] == -1) cout << 0;
        else cout << a[i]; 
    }
    return 0;
}

D

带权并查集

有n 个人,m对朋友关系,k对封锁关系(黑名单),问你每个人有多少个候选朋友

要求候选朋友在同一个朋友圈内,且两人无直接的联系

候选朋友的数量= 间接朋友的数量 - 不可能是候选朋友的数量 - 自己

ans 记录不可能是候选朋友的数量 其中包括,黑名单的人 和 自己的朋友数量。

size 记录整个连通块一共有多少人

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int f[N],size[N],ans[N],n,m,k;
int find(int x) {
    return x == f[x] ? x : f[x] = find(f[x]);
}
void merge(int x,int y) {
    int xx = find(x);
    int yy = find(y);
    if(xx != yy) {
        f[xx] = yy;
        size[yy] += size[xx];
    }
}
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> n >> m >> k;
    for(int i = 1;i <= n; ++i) f[i] = i,size[i] = 1;
    int x,y;
    while(m --) {
        cin >> x >> y;
        ans[x] ++,ans[y] ++;// 把自己给计算上
        merge(x,y);
    }
    while(k --) {
        cin >> x >> y;
        if(find(x) == find(y)) {// 在同一个朋友圈内,才算黑名单
            ans[x] ++;
            ans[y] ++;
        }
    }
    for(int i = 1;i <= n; ++i) {
        cout << size[find(i)] - ans[i] - 1 <<' ';
    }
    return 0;
}

E

线段树,树状数组

有一串字符,我们可以执行两种操作:

1、替换某个位置的字符

2、查询某一段区间不同字符的个数

用26颗树来维护区间信息

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 5e5 + 10;
char s[N];
int tr[30][N];
int n,q,op;
int lowbit(int x) {
    return x & -x;
}
void update(int x,int v,int a[]) {
    for(int i = x;i <= n;i += lowbit(i)) a[i] += v;
    // 在第x个位置更新 树a,每个自低向上+1,代表该字符出现的位置
}
int query(int x,int a[]) {
    int res = 0;
    for(int i = x;i >= 1;i -= lowbit(i)) {
        res += a[i];
    }
    // 在1 - x 这个区间,该字符出现的次数,肯定要在该字符的树上查询,自顶向下
    return res;
}
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin >> n >> s >> q;
    for(int i = 0;i < n; ++i) update(i + 1,1,tr[s[i] - 'a']);
    while(q --) {
        cin >> op;
        if(op == 1) {
            int i;
            char c;
            cin >> i >> c;
            // 先把原来这个区间全部减去 1
            update(i,-1,tr[s[i - 1] - 'a']);
            s[i - 1] = c;// 修改字符串
            update(i,1,tr[c - 'a']);// 修改区间内的信息
        }
        else {
            int l,r,cnt = 0;
            cin >> l >> r;
            for(int i = 0;i < 26; ++i) {
                if(query(r,tr[i]) - query(l - 1,tr[i]) > 0) cnt ++;
            }
            cout << cnt << endl;
        }
    }
    return 0;
}
posted @ 2020-03-14 11:52  lukelmouse  阅读(186)  评论(0编辑  收藏  举报