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;
}