Atcoder Beginner Contest 451

A:illegal

根据题意直接判断字符串长度是否等于5,按要求输出即可。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<bits/stdc++.h>
using namespace std;
#define int long long
string s;

signed main()
{
cin>>s;
int len=s.size();
if(len%5==0) cout<<"Yes";
else cout<<"No";
return 0;
}

B:Personnel Change

将部门编号作为下标建立数组tong,对于每条输入,tong[Ai] − −, tong[Bi] + +,最后输出数组中所有值即可。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1000002;
int n,m,a,b;
int tong[maxn];
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a>>b;
tong[a]--; tong[b]++;
}
for(int i=1;i<=m;i++) cout<<tong[i]<<endl;
return 0;
}

C:Understory

题目要求维护两个操作,插入一个带权元素与删除小于某个权值的所有元素。观察数据范围可知题目需要log级别的算法。我们维护一个优先队列,插入直接插入,删除的时候只需要重复判断堆顶元素和删除阈值的大小关系即可,这样就避免了重复访问。复杂度O(QlogQ)。用实现时可以选择重载运算符或直接插入负值。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1000002;
int t,h,op;
priority_queue<int> q;
signed main()
{
cin>>t;
while(t--)
{
cin>>op>>h;
if(op==1) q.push(-h);
if(op==2)
{
while(!q.empty())
{
int now=q.top();
if(-now<=h) q.pop();
else break;
}
}
cout<<q.size()<<endl;
}
return 0;
}

D:Concat Power of 2

首先观察数据范围得到N < 1e9,于是我们知道由拼接构成N的每个部分都是不会超过1e9的。所以我们直接预处理出所有可能的“拼图”,之后直接暴搜+剪枝(超过1e9便不继续搜索)便足以通过本题。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=100;
int n,tot,total;
int a[maxn],len[maxn],final[10000002],vis[maxn],p10[12];
int getLen(int now)
{
int sum=0;
while(now)
{
sum++;
now/=10;
}
return sum;
}
set<int> mp;
void dfs(int now)
{
if(now>0 && mp.count(now)==0)
{
final[++total]=now;
mp.insert(now);
}
for(int i=1;i<=tot;i++)
{
int nxt=a[i]+now*p10[len[i]];
if(nxt<=1e9) dfs(nxt);
}
}
signed main()
{
cin>>n;
for(int i=0;i<=50;i++)
{
if((1<<i)<=1e9) a[++tot]=pow(2,i);
else break;
}
p10[0]=1;
for(int i=1;i<=10;i++) p10[i]=p10[i-1]*10;
for(int i=1;i<=tot;i++) len[i]=getLen(a[i]);
dfs(0); sort(final+1,final+1+total);
cout<<final[n];
return 0;
}

E:Tree Distance

首先我们观察一个性质,对于所有aij里面最小的那一个,肯定是要把i, j直接连起来的,且边权为aij。这个结论是易证的,因为首先树上两点之间的路径仅有一条,如果能够满足i, j通过其他点(假设为点z)连起来且满足边权要求,则最后肯定不满足i, z; z, j之间的边权要求,因为i, j是距离要求最小的一对点。所以我们推广这个结论,即如果有ai, j < am, n,一定要优先满足i, j之间的边权要求。所以我们直接按照ai, j大小排序,如果两个点已经联通了,那么就跳过这条边(他们能联通肯定是为了满足前面边权更小的点对更严苛的要求)最后check是否满足距离和题目要求相同;如果两个点还没有联通,因为我们考虑到的这一对点已经是当前aij最小的点对了,我们肯定要把这一对点直接连起来(这个结论就是最开始证明的结论)。这个维护连通性的过程可以由并查集完成,在最后以每个点为根分别进行一次dfs完成check工作即可。时间复杂度O(n2logn)

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3002;
struct nodd {
int u,v,val;
}edge[maxn*maxn];
struct nodd2 {
int to,val;
};
vector<nodd2> tree[maxn];
int n,tot,flag;
int a[maxn][maxn],fa[maxn],final[maxn][maxn],dis[maxn];
bool cmp(nodd x,nodd y) { return x.val<y.val; }
int find(int x)
{
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void dfs(int now,int dep,int f)
{
dis[now]=dep;
int len=tree[now].size()-1;
for(int i=0;i<=len;i++)
{
int to=tree[now][i].to;
if(to==f) continue;
dfs(to,dep+tree[now][i].val,now);
}
return ;
}
signed main()
{
cin>>n;
for(int i=1;i<=n-1;i++)
{
for(int j=i;j<=n;j++)
{
if(i==j) continue;
cin>>a[i][j]; a[j][i]=a[i][j];
edge[++tot]=nodd{i,j,a[i][j]};
}
}
for(int i=1;i<=n;i++) fa[i]=i;
sort(edge+1,edge+1+tot,cmp);
for(int i=1;i<=tot;i++)
{
if(find(edge[i].u)!=find(edge[i].v))
{
fa[find(edge[i].u)]=find(edge[i].v);
tree[edge[i].u].push_back(nodd2{edge[i].v,edge[i].val});
tree[edge[i].v].push_back(nodd2{edge[i].u,edge[i].val});
}
}
for(int i=1;i<=n;i++)
{
memset(dis,0,sizeof(dis)); dfs(i,0,0);
for(int j=1;j<=n;j++) if(dis[j]!=a[i][j]) flag=1;
}
if(flag==1) printf("No");
else printf("Yes");
return 0;
}

F:Make Bipartite 3

待补题,赛时思考方向是要用并查集在线的去维护不同连通块的一些性质的。