A - Lex String

Problem - A - Codeforces

题意

给定两个没有相同字符的字符串 $a,b$ 。每回合轮流从任意一个字符串中任意取一个字符,并插入到一个字符串 $c$ 的末尾。要求不能连续取同一个字符串中的字符大于 $k$ 次,如果两个字符串中有一个空了,

题解

模拟即可,注意题目中强调的细节即可。

B - Mystic Permutation

Problem - B - Codeforces

题意

给出一个排列 $[1,n]$ ,要求构造一个排列 $[1,n]$,使得这两个排列之间的任意一个相同位置的元素都不相同,且满足这个排列的字典序最小。 如果无法构造出这样的序列则输出 $-1$ 。

题解

正常贪心即正解,优先摆小的,如果相同就摆下一个,如果是最后一个就和前一个交换。

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
inline void Work() {
if(n == 1) {
printf("-1\n");
while(!q.empty()) q.pop();
return ;
}
for(int i = 1; i <= n; i++) {
int tp = q.top(); q.pop();
if(tp == a[i]) {
if(q.empty()) {
b[i] = tp;
swap(b[i], b[i-1]);
}
else {
b[i] = q.top(); q.pop();
q.push(tp);
}
}
else {
b[i] = tp;
}
}
while(!q.empty()) q.pop();
for(int i = 1; i <= n; i++) {
if(b[i] == a[i]) {
printf("-1\n");
return ;
}
}
for(int i = 1; i <= n; i++) {
printf("%d ", b[i]);
}
printf("\n");
}

C - Infected Tree

Problem - C - Codeforces

题意

给定一棵以 $1$ 号节点为根的二叉树,总节点个数为 $n$ 。

现在 $1$ 号节点感染了病毒,病毒每一回合都会去感染与该节点直接相连的节点,而你在这一回合里可以选择删除任意一个没有被病毒感染(尚未被删除)的点,这样就断开了它与其直接相连的点得关系.

询问最多可以有多少不被病毒感染的点,被删除的点不算做不被病毒感染的点

题解

一眼树形DP。设置状态 $dp[u]$ 表示:以 $i$ 为根的子树中,若 $i$ 被感染了,最多能保留多少个节点。

考虑转移。注意到这是一颗二叉树,所以转移就很简单了:$dp[u]=\max(dp[lc]+sz[rc]-1,dp[rc]+sz[lc]-1)$ 。

实际意义如图所示:

删去右端点示意

D - Lena and Matrix

Problem - D - Codeforces

题意

给定一个由字符 WB 组成的 $n\times m$ 的矩阵。求这样一个点的坐标,满足其到图中任何一个 B 的最大曼哈顿距离最小。

题解

首先尝试平均数和中位数,发现都不对,卡掉他也很简单,让大多数的点聚集在一个地方,然后放一个点在一个很远很远的地方,这样就能卡掉平均数和中位数。

接下来考虑正解。我们会发现题目让我们维护的答案核心其实是下边的那个式子:

众所周知,曼哈顿距离不容易维护的话我们还有另外一个常用的距离:切比雪夫距离。如果用切比雪夫距离表示的话,答案就显而易见了:

简单转化一下就可以得到:$\max(\max(|X-x_i|), \max(|Y-y_i|))$。

这个显然非常容易维护,直接把最后的答案得出后转换回曼哈顿即可。

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
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=2005;
LL T,n,m,a[N][N],ansx,ansy;
vector<LL>v1,v2;
char c;
LL cal(LL xx,LL yy)
{
return max({xx-v1[0],yy-v2[0],v1[v1.size()-1]-xx,v2[v2.size()-1]-yy});
}
int main()
{
cin>>T;
while(T--)
{
cin>>n>>m;
ansx=1e9;
v1.clear(),v2.clear();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>c;
if(c=='B')
{
v1.push_back(j-i);
v2.push_back(i+j);
}
}
}
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
LL xx=j-i,yy=i+j;
if(cal(xx,yy)<cal(ansy-ansx,ansy+ansx))
{
ansx=i,ansy=j;
}
}
}
cout<<ansx<<' '<<ansy<<endl;
}

}

E - ANDfinity

Problem - E - Codeforces

题意

从计算机科学系毕业后, Vlad 被奖与一个由 $n$ 个非负整数组成的数组 $a_1,a_2, \dots , a_n$。他很自然地想到构建一个有 $n$ 个点,编号为 $1,2,\dots,n$ 的图。点 $i$ 和 $j$ 之间有边当且仅当 $a_i\& a_j >0$,其中 $\&$ 表示按位与。

Vlad 希望这张图连通,虽然最初可能不是这样。为了使图连通,他可以对这个数组做下列两种操作:

  1. 选择一个元素 $a_i$ 并将它加一。
  2. 选择一个元素 $a_i$ 并将它减一(仅能在 $a_i>0$ 时做此操作)。

可以证明存在一个有穷的操作序列使得这张图连通。所以,你能帮 Vlad 找到最少的可能操作数以达成这个目标并给出操作方法吗?

题解

首先注意到 $0$ 一定要变为 $1$ 才可以联通,鱼逝先优先变 $0$ 。

接下来观察性质。

考虑贪心,对于 lowbit 最大的数,对其减一,如果不止一个,那么随机取一个加一即可。

证明很简单,因为 lowbit 最大的数减一以后,剩下的几位就都变成了一;如果还有的话就会连不上,我们加一就有一定能连上。

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Problem: E. ANDfinity
// Contest: Codeforces - Codeforces Round #798 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1689/E
// Memory Limit: 256 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)

//回家?我没有家可以回,我没有退路。
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int a[2003],n,ans,x,s;
bool vis[2003];
int fa[2003];
void dfs(int x)
{
vis[x]=1,++s;
for(int i=1; i<=n; ++i)
if((a[i]&a[x])&&!vis[i])
dfs(i);
return ;
}
int L(int x){return x&(-x);}
int find(int x){return fa[x]==x?x:(fa[x]=find(fa[x]));}
bool chk()
{
for(int i=1; i<=n; ++i) fa[i]=i;
for(int s=1; s<=536870912; s<<=1)
{
int fir=n;
for(int i=1; fir==n&&i<n; ++i) if(a[i]&s) fir=i;
int A=find(fir);
for(int i=fir+1; i<=n; ++i) if(a[i]&s) fa[find(i)]=A;
}
for(int i=2; i<=n; ++i) if(find(i)!=find(1)) return 0;
return 1;
}
signed main()
{
for(int T=read();T--;)
{
n=read(),ans=x=s=0;
for(int i=1; i<=n; ++i) vis[i]=0;
for(int i=1; i<=n; ++i)
(!(a[i]=read()))&&(++ans,a[i]=1),
x=max(x,L(a[i]));
dfs(1);
if(s==n)
{
printf("%d\n",ans);
for(int i=1; i<=n; ++i) printf("%d ",a[i]);
puts("");
}
else
{
int ovo=1;
for(int i=1; i<=n; ++i)
{
//check: --a[i]
--a[i];
if(chk()){ovo=0;break;}
//check: ++a[i]
++a[i],++a[i];
if(chk()){ovo=0;break;}
--a[i];
}
if(!ovo)
{
printf("%d\n",ans+1);
for(int i=1; i<=n; ++i) printf("%d ",a[i]);
puts("");
continue;
}
for(int i=1; i<=n; ++i)
if(L(a[i])==x)
{
if(ovo)
--a[i],ovo=0;
else
{
++a[i];
break;
}
}
printf("%d\n",ans+2);
for(int i=1; i<=n; ++i) printf("%d ",a[i]);
puts("");
}
}
return 0;
}