A. Uniform String
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int t,n,k;
void solve(){
int cnt = 0;
for(int i = 1; i <= n; ++ i){
printf("%c", 'a' + (cnt++ % k));
}
puts("");
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n, &k);
solve();
}
return 0;
}
B. Teams Forming
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,a[N];
void solve(){
sort(a + 1, a + n + 1);
int ans = 0;
for(int i = 2; i <= n; i += 2){
ans += a[i] - a[i - 1];
}
printf("%d\n", ans);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
return 0;
}
C. Prefixes and Suffixes
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 200 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,pos[N];
string s[N];
char ans[N];
bool cmp(int i,int j){
return s[i].size() > s[j].size();
}
bool check(int x){
string s1,s2;
if(x)s1 = s[pos[1]], s2 = s[pos[2]], ans[pos[1]] = 'P', ans[pos[2]] = 'S';
else s1 = s[pos[2]], s2 = s[pos[1]], ans[pos[1]] = 'S', ans[pos[2]] = 'P';
int len = n - 2;
for(int i = 3; i <= 2 * n - 2; i += 2){
int idx1 = pos[i],idx2 = pos[i + 1];
if(s1.substr(0,len) == s[idx1] && s2.substr(n - len - 1) == s[idx2]){
ans[idx1] = 'P', ans[idx2] = 'S';
}
else if(s1.substr(0,len) == s[idx2] && s2.substr(n - len - 1) == s[idx1]){
ans[idx1] = 'S', ans[idx2] = 'P';
}
else{
return false;
}
-- len;
}
return true;
}
void solve(){
sort(pos + 1, pos + 2 * n - 1,cmp);
if(check(1) || check(0)){
ans[2 * n - 1] = '\0';
cout << (ans + 1) << endl;
}
}
int main(){
cin >> n;
for(int i = 1; i <= 2 * n - 2; ++ i){
cin >> s[i];
pos[i] = i;
}
solve();
return 0;
}
D1. Great Vova Wall (Version 1)
-
题意 有
n
n
n个墙,现在你可以砌砖,砖的大小为
2
×
1
2\times 1
2×1。砖可以放置在等高墙的相邻部分,使得这两个墙的高度都增加
1
1
1,在这个版本中,你还可以垂直放置,使得墙的任何部分的高度都增加
2
2
2。问你是否可以使得墙的所有部分都有相同的高度,且墙里面没有空的空间。 -
解题思路 对于单个墙来说,我们垂直放置砖块不能改变奇偶性。对于两个相邻的墙且奇偶性相同的,我们可以先垂直放置再水平放置使其相同高。对于所有的墙也一样。所以我们只在乎墙高的奇偶性。然后变成一个奇偶匹配问题即可。即经典的括号匹配问题。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,x;
int Stack[N],top,bottom;
void solve(){
if(top - bottom <= 1){
puts("YES");
}
else{
puts("NO");
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &x);
x %= 2;
if(top - bottom == 0 || Stack[top - 1] != x){
Stack[top ++] = x;
}
else{
-- top;
}
}
solve();
return 0;
}
D2. Great Vova Wall (Version 2)
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,x,maxx;
int Stack[N],top,bottom;
bool flag = false;
void solve(){
if(top - bottom > 1 || (top - bottom && Stack[top - 1] < maxx))flag = true;
printf("%s\n", flag ? "NO" : "YES");
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &x);
maxx = max(maxx,x);
if(top - bottom){
if(Stack[top - 1] == x){
-- top;
}
else if(Stack[top - 1] < x){
flag = true;
break;
}
else{
Stack[top ++] = x;
}
}
else{
Stack[top ++] = x;
}
}
solve();
return 0;
}
E. Minimal Diameter Forest
-
题意 给你一个森林,其中包含
n
n
n个结点。现在需要你添加边使其成为一颗树,并且树的直径尽可能小。树的直径称为:其任意一对顶点之间最短路径中的最大边数。 -
解题思路 拼接这些树我们肯定是需要找到每个树的关键点。这里这个关键点不是树的中心,而是该点到其他点的最短路径的最大值最小。 然后连接这些树我们也肯定不是以链的方式来串起来,而是通过: 这种方式串起来才是最优的。 经过以上分析,首先,我们需要找到每个树的关键点,这个我们可以先确定每个点所属的连通块。然后根据
a
n
s
1
ans1
ans1数组来确定最小值以及该连通块的关键点,求最短路径我们同样可以通过
d
f
s
dfs
dfs或者
b
f
s
bfs
bfs实现。当然我们也要保存每个连通块的最长路径,因为这也会作为树的直径的参考因素。 考虑完上述,我们考虑拼接点后的直径最长是多少,其中有贡献的则是最长的
a
n
s
1
[
1
]
ans1[1]
ans1[1]和次长的
a
n
s
1
[
2
]
ans1[2]
ans1[2]通过
1
1
1这个连通块的关键点连接,所以会多出一条边,即直径为
a
n
s
1
[
1
]
+
a
n
s
1
[
2
]
+
1
ans1[1] + ans1[2] + 1
ans1[1]+ans1[2]+1,还有一个则是第二长的
a
n
s
1
[
2
]
ans1[2]
ans1[2]和
a
n
s
1
[
3
]
ans1[3]
ans1[3]通过
1
1
1这个连通块的关键点连接,所以会多出来两条边,即直径为
a
n
s
1
[
2
]
+
a
n
s
1
[
3
]
+
2
ans1[2] + ans1[3] + 2
ans1[2]+ans1[3]+2,取个max即可。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct edge{
int to, next;
} edges[N];
int head[N],tot;
int n,m,belong[N],cnt;
int ans1[N],ans2[N],in[N];
int id[N];
void add(int u,int v){
edges[++ tot].to = v;
edges[tot].next = head[u];
head[u] = tot;
}
bool cmp(int i,int j){
return ans1[i] > ans1[j];
}
void dfs1(int u){
belong[u] = cnt;
for(int i = head[u]; i; i = edges[i].next){
int v = edges[i].to;
if(!belong[v])dfs1(v);
}
}
int dfs2(int u,int fu,int depth){
int maxx = depth;
for(int i = head[u]; i; i = edges[i].next){
int v = edges[i].to;
if(v == fu)continue;
maxx = max(maxx,dfs2(v,u,depth + 1));
}
return maxx;
}
void solve(){
fill(ans1, ans1 + N, INF);
for(int i = 1; i <= n; ++ i){
if(!belong[i]){
++ cnt;
dfs1(i);
}
}
for(int i = 1; i <= n; ++ i){
int maxx = dfs2(i,-1,0);
if(maxx < ans1[belong[i]]){
ans1[belong[i]] = maxx;
in[belong[i]] = i;
}
ans2[belong[i]] = max(ans2[belong[i]], maxx);
}
int res = 0;
for(int i = 1; i <= cnt; ++ i){
id[i] = i;
res = max(res,ans2[i]);
}
sort(id + 1, id + 1 + cnt,cmp);
if(cnt >= 2){
res = max(res, ans1[id[1]] + ans1[id[2]] + 1);
}
if(cnt >= 3){
res = max(res, ans1[id[2]] + ans1[id[3]] + 2);
}
printf("%d\n", res);
for(int i = 2; i <= cnt; ++ i){
printf("%d %d\n", in[id[1]], in[id[i]]);
}
}
int main(){
scanf("%d%d", &n, &m);
int u,v;
for (int i = 1; i <= m; ++ i){
scanf("%d%d", &u, &v);
add(u,v), add(v,u);
}
solve();
return 0;
}
F. Tree with Maximum Cost
-
题意 有一个
n
n
n个结点的无根树,树的每个结点都有一个权值。 结点i的权值为
a
i
a_i
ai?。
d
i
s
t
(
x
,
y
)
dist(x,y)
dist(x,y)定义为结点
x
x
x到结点
y
y
y的距离,即结点
x
x
x到结点
y
y
y的简单路径上边的数量。 以结点
v
v
v为根的树的价值定义如下:
∑
i
=
1
n
d
i
s
t
(
i
,
v
)
?
a
i
\sum_{i=1}^ndist(i,v)·a_i
∑i=1n?dist(i,v)?ai? 请你确定以某个结点为根时树的最大价值。 -
解题思路 我们可以先通过
d
f
s
dfs
dfs预处理出
1
1
1作为根节点的价值和
s
u
m
sum
sum数组,
s
u
m
[
u
]
sum[u]
sum[u]则表示以
u
u
u为根节点的子树总权值。我们的技巧是通过一开始定的根
1
1
1,然后通过dfs重新生根更新当前的总和。 为什么呢?我们来解释一下。假设原来的根为
u
u
u,现在将根转为
u
u
u的孩子结点
v
v
v。 至此,则此题得解。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct edge{
int to,next;
}edges[N << 1];
int head[N],tot;
int n,a[N];
ll res,sum[N];
void add(int u,int v){
edges[++ tot].next = head[u];
edges[tot].to = v;
head[u] = tot;
}
void dfs1(int u,int fu,int depth){
res += 1LL * depth * a[u];
sum[u] = a[u];
for(int i = head[u]; i; i = edges[i].next){
int v = edges[i].to;
if(v == fu)continue;
dfs1(v,u,depth + 1);
sum[u] += sum[v];
}
}
void dfs2(int u,int fu,ll ans){
res = max(res,ans);
for(int i = head[u]; i; i = edges[i].next){
int v = edges[i].to;
if(v == fu)continue;
ll temp = ans + sum[u] - 2 * sum[v];
sum[u] -= sum[v];
sum[v] += sum[u];
dfs2(v,u,temp);
sum[v] -= sum[u];
sum[u] += sum[v];
}
}
void solve(){
dfs1(1,-1,0);
dfs2(1,-1,res);
printf("%lld\n", res);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
int u,v;
for(int i = 1; i < n; ++ i){
scanf("%d%d", &u, &v);
add(u,v), add(v,u);
}
solve();
return 0;
}
|