Educational Codeforces Round 126

 

A. Array Balancing

You are given two arrays of length n: a1,a2,…,an and b1,b2,…,bn.

You can perform the following operation any number of times:

  1. Choose integer index i (1≤i≤n);

  1. Swap ai and bi.

What is the minimum possible sum |a1−a2|+|a2−a3|+⋯+|an−1−an| + |b1−b2|+|b2−b3|+⋯+|bn−1−bn| (in other words, ∑i=1n−1(|ai−ai+1|+|bi−bi+1|)) you can achieve after performing several (possibly, zero) operations?

给你两个长为n的数组 a1,a2,…,an 和 b1,b2,…,bn。可以操作任意次:选择任意i,交换ai和bi。求操作后可能得到的最小|a1−a2|+|a2−a3|+⋯+|an−1−an| + |b1−b2|+|b2−b3|+⋯+|bn−1−bn| 。

 

每一个数处于第一个数组还是第二个数组只对它前面的一位和后面的一位有影响。后面的一位可以选择交换来消除影响,因此考虑这一位是否交换的时候不用考虑对后一位的影响,只需要选择对前一位来说的最佳答案就可以。

#include<cstdio>
using namespace std;
const int N=27;
int a[N],b[N],n,t;
int abs(int a){
if(a<0) return -1*a;
else return a;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
long long ans=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=2;i<=n;i++){
if(abs(b[i]-a[i-1])+abs(a[i]-b[i-1])<abs(a[i]-a[i-1])+abs(b[i]-b[i-1])){
int tmp=b[i];
b[i]=a[i];
a[i]=tmp;
}
ans += abs(a[i]-a[i-1])+abs(b[i]-b[i-1]);
}
printf("%lld\n",ans);
}
return 0;
}

 

 

B. Getting Zero

Suppose you have an integer v. In one operation, you can:

  • either set v=(v+1)mod32768

  • or set v=(2⋅v)mod32768.

You are given n integers a1,a2,…,an. What is the minimum number of operations you need to make each ai equal to 0?

对一个整数v,每次操作可以选择:使 v=(v+1) mod 32768,或 v=(2⋅v) mod 32768。求使v变成0的最小操作数。

 

32768=2^15。因此对任意一个数执行15次操作2,即 v·32768 mod 32768,都能使其归零。所以使任何数归零的最小操作数有可能的最大值都是15。

在此基础上,如果执行若干次操作1可以使 v 变成2的次方数的整数倍,然后再执行若干次操作2,就有可能省去一些步骤。

直接去求第二种可能的答案,如果过程中超过了15步,就说明这种方式不会得到更好的答案。

注意:32768也需要执行一次操作才能变成0。

#include<cstdio>
using namespace std;
const int N = 1<<16;
int t,a,ans[N];
int main(){
for(int i=1;i<=32768;i++) ans[i]=15;
for(int i=1,j=0;i<=32768;i<<=1,j++){
ans[i]=15-j;
for(int k=2*i;k<=32768;k=k+i){
if(ans[k]>ans[i]) ans[k]=ans[i];
}
}
ans[32768]=1;
ans[32767]=1;
for(int i=32766;i>=1;i--){
if(ans[i]>ans[i+1]+1) ans[i]=ans[i+1]+1;
}
scanf("%d",&t);
while(t--){
scanf("%d",&a);
printf("%d ",ans[a]);
}
return 0;
}

 

 

C. Water the Trees

 

There are n trees in a park, numbered from 1 to n. The initial height of the i-th tree is hi.

You want to water these trees, so they all grow to the same height.

The watering process goes as follows. You start watering trees at day 1. During the j-th day you can:

  • Choose a tree and water it. If the day is odd (e.g. 1,3,5,7,…), then the height of the tree increases by 1. If the day is even (e.g. 2,4,6,8,…), then the height of the tree increases by 2.

  • Or skip a day without watering any tree.

Note that you can't water more than one tree in a day.

Your task is to determine the minimum number of days required to water the trees so they grow to the same height.

You have to answer t independent test cases.

公园里有n棵树,从1到n编号。第i棵树的初始高度是hi。要对这些树浇水,使所有树长到同一高度。每天可以选一棵树浇水,奇数天可以使这棵树长高1,偶数天可使这棵树长高2。可以跳过某些天不浇水。确定使所有树长到同一高度的最小天数。

 

要使一棵树长高2,可以选择在一个偶数天浇水,或在两个奇数天浇水。要使一棵树长高1,则必须在一个奇数天浇水。

设第i棵树到目标高度的距离是diff[i]。当diff[i]为奇数时,说明为了让这棵树长到目标高度,必须至少在一个奇数天浇水。其他则既可以在一个偶数天浇水,也可以分拆成在两个奇数天浇水。

统计必须在奇数天浇水的次数。先默认剩下的高度差都使用偶数天来浇水。

然后可能会得到:

  1. 奇数天>偶数天:奇 偶 奇 偶 奇 偶 ... 奇 偶 奇 (空) 奇 (空) 奇 (空) 奇

    这种情况下,把任何偶数天浇水拆成两个奇数天浇水都只能增加总天数,所以这就是最佳答案。

    总天数=奇数天*2-1。

  2. 奇数天=偶数天:奇 偶 奇 偶 奇 偶 ... 奇 偶 奇 偶

    同样,把任何偶数天浇水拆成两个奇数天浇水都只能增加总天数。

    总天数=奇数天*2。

  3. 奇数天<偶数天:奇 偶 奇 偶 奇 偶 ... 奇 偶 (空) 偶 (空) 偶 (空) 偶

    在第一个空出现之前,都没有优化空间了,所以只需要考虑第一个空及更往后的部分。

    分情况讨论:

    1. 多了一个偶数天:(空) 偶——无法优化

    2. 多了两个偶数天:(空) 偶 (空) 偶——奇 偶 奇

    3. 多了三个偶数天:(空) 偶 (空) 偶 (空) 偶 ——奇 偶 奇 偶

    4. 多了更多偶数天:每三个偶数天可以拆成“奇 偶 奇 偶”。对三取模的部分再按照情况1或情况2来考虑。

目标高度可能是所有树中最高的高度,也可能是最高的高度+1;后者在有些情况下可以通过减少必须在奇数天浇水的数量来减少总天数。(如:1 1 1 1 1 1 2)对两种可能的目标高度分别计算,取最优答案即可。

 

#include<cstdio>
using namespace std;
const int N=300007;
int t,n,h[N],diff[N];
long long get_ans(int tar){
long long cnt1=0,cnt2=0;
for(int i=1;i<=n;i++){
int x=tar-h[i];
cnt1+=x%2;
cnt2+=x/2;
}
if(cnt1>cnt2) return cnt1*2-1;
if(cnt1==cnt2) return cnt2*2;
long long extra2=cnt2-cnt1;
cnt1+=extra2/3*2;
cnt2-=extra2/3;
extra2=cnt2-cnt1;
if(extra2==2) return 2*cnt2-1;
return 2*cnt2;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int maxn=0;
for(int i=1;i<=n;i++){
scanf("%d",&h[i]);
if(h[i]>maxn) maxn=h[i];
}
long long ans1=get_ans(maxn);
long long ans2=get_ans(maxn+1);
if(ans2<ans1) ans1=ans2;
printf("%lld\n",ans1);
}
return 0;
}

 

 

下一次的目标是在考场上做完C题,至少看一眼D题。

 

posted @ 2022-04-13 23:34  IvyLH03  阅读(100)  评论(0)    收藏  举报