Codeforces Round #633 (Div. 2) A-D
A. Filling Diamonds
题目挺长的,乍一看,好像很难,但是这题其实只用输出n。
他问的是有多少种方式填充完这张图,其实就是选取直着的菱形的位置。
B. Sorted Adjacent Differences
题目的意思是给你一个长为n的数组a,要你把这个a数组排序成|
a
1
a_{1}
a1−
a
2
a_{2}
a2|≤|
a
2
a_{2}
a2−
a
3
a_{3}
a3|≤…≤|
a
n
−
1
a_{n-1}
an−1−
a
n
a_{n}
an|,并输出出来。
解题方式就是先把这个数组sort一下,如果n是奇数就先输出最中间的数,然后平分为左右两块,先输出一个右,后输出一个左,交替进行,直到输出完为之。
证明很容易证,排序之后,从中间开始,左右两块的差值肯定是递增的。
主要代码:
const int N = 1e5+5;
int a[N];
int T;cin>>T;
while(T--){
int fi = 1;
int n;cin>>n;
for(int i = 0;i<n;++i)cin>>a[i];
sort(a,a+n);
int i,j;
if(n%2){
cout<<a[n/2]<<' ';
i=n/2-1,j=n/2+1;
}else i=n/2-1,j=n/2;
while(i>=0){
if(fi)fi=0;
else cout<<' ';
cout<<a[j]<<' '<<a[i];
i--,j++;
}
cout<<'\n';
}
C. Powered Addition
题目的意思是给你一个长为n的数组a,每x秒钟,你可以选择这个数组a的任意一个子序列(不连续),
并对他们进行加
2
x
−
1
2^{x-1}
2x−1的操作一次,或者什么都不做,问x最少为多少,可以使这个序列变成,不下降序列。
解题方法就是求,这个数组的数的最大差值。
先让ma初始化为a[0],用一个标志表示是否有
a
i
a_i
ai<
a
a
i
−
1
a_{a_i-1}
aai−1,从1开始遍历,如果出现
a
i
a_i
ai<
a
a
i
−
1
a_{a_i-1}
aai−1,更新最大值为max(ma,
a
i
a_i
ai-
a
a
i
−
1
a_{a_i-1}
aai−1),标志为0,如果出现
a
i
a_i
ai>ma,更新ma为
a
i
a_i
ai,直到遍历结束,特判n为1的情况即可。
主要代码:
const int N = 1e5+5;
int a[N];
int T;cin>>T;
while(T--){
int n;cin>>n;
int ind = -1;
int ans = -INF;
for(int i = 0;i<n;++i)cin>>a[i];
if(n==1)cout<<0;
else {
int ma = a[0];
bool flag = 1;
for(int i = 1;i<=n;++i){
if(a[i]<a[i-1])flag = 0;
ans = max(ans,ma - a[i]);//更新最大值
if(a[i]>ma)ma=a[i];//更新ma
}
if(flag)cout<<0;
//下面一串是求x
else{
int res = 0;
int cnt=1;
while(ans>0){
++res;
ans-=cnt;
cnt*=2;
}
cout<<res;
}
}
cout<<'\n';
}
D - Edge Weight Assignment
本题的题意是给你一颗有n个节点的树,然后所有的边都可以自己赋权值,要求满足各个叶子节点之间的路径上的权值的异或为0,求所用的权值的种类的最小值和最大值。
本题题意较难懂,但是异或很容易知道,奇数个数的异或要为0,则至少要3种,偶数只需要一种,则题目的最小值可以转化为,找一个根,然后求每个叶子节点的深度,如果深度都为偶数或者奇数,则最小值为1,否则为3,因为可以以这个根为中心,每个叶子到这个根的深度的奇偶性相同,则为偶数个数,否则为奇数个数,求深度用dfs就行了。最大值很好搞,因为一个数只有和自己本身异或才为0,然后根据前面的结论可以得到最大值 = n - 1 -
∑
\sum
∑(连在同一父节点的叶子数-1)。
主要代码:
vector<int>edge[N];//用于储存每个节点相邻的节点
int d[N], cnt[N], dep[N], flag[2];
void dfs(int v, int fa) {
for(auto& it:edge[v]) {
int u = it;
if (u != fa) {
dep[u] = dep[v] + 1;
dfs(u, v);
}
}
if (d[v] == 1)flag[dep[v] & 1] = 1;//统计叶子节点的深度,奇偶数的情况
}
int main() {
int n; cin >> n;
map<int, int>lef;
for(int i = 1;i<n;++i) {
int v, u; cin >> v >> u;
edge[v].PB(u), edge[u].PB(v);
lef[v] = u, lef[u] = v;
++d[v], ++d[u];//统计每一个节点的度数
}
int root;
for(int i = 1;i<=n;++i) {
if (d[i] > 1)root = i;//用度数>1的作为根节点
else if (d[i] == 1)++cnt[lef[i]];//统计连在同一个父节点的叶子节点数
}
int ma = n - 1;
for(int i = 1;i<=n;++i) {
if (cnt[i] > 1)ma -= cnt[i] - 1;//减去不符合的贡献
}
dfs(root, -1);
int mi = 1;
if (flag[0] && flag[1])mi = 3;
cout << mi << ' ' << ma;
return 0;
}