Educational Codeforces Round 126 (Div. 2)题解

本文介绍了三道算法竞赛题目,包括数组平衡、数值操作达到零和树的高度平衡。第一题要求通过交换数组元素使得相邻元素差值和最小;第二题涉及加一和乘二操作,目标是最小步数使数值为零;第三题讨论如何在限定操作下使所有树达到相同高度。每题都提供了关键思路和解题代码。
摘要由CSDN通过智能技术生成

A. Array Balancing

题意:给出a,b两个数组可以交换两队数组内位置相同的数

求相邻两数绝对值和的最小值

对于每个点求交换与不交换的贡献值取min即可

#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
#define int long long
const int MAXN=37;
int a[MAXN],b[MAXN];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        int ans=0;
        for(int i=2;i<=n;i++)
            ans+=min(abs(a[i]-a[i-1])+abs(b[i]-b[i-1]),abs(a[i]-b[i-1])+abs(b[i]-a[i-1]));
        cout<<ans<<endl;
    }
    AC
}

B. Getting Zero

题意:给出一个数和取模32768,有两个操作加一取模和乘二取模

问最小次数使该数变为0

注意到模数为32768是2的15次,所以对于一个数一直乘二最大也只需15次,然后从0-15暴力枚举加一次数

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define AC return 0;
#define int long long
const int MAXN=5e4+7;
const int MOD=32768;
int a[MAXN];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++){
            int ans=15;
            for(int j=0;j<=15;j++){
                int num=(a[i]+j)%MOD;int cnt=0;
                while(num!=0){
                    num=num*2%MOD;
                    cnt++;
                }
                ans=min(ans,j+cnt);
            }
            
            cout<<ans<<" ";
        }
    
    AC
}

C. Water the Trees

题意:给出n颗树的高度,在一天内你可以选择浇树或者不浇,偶数天浇树树长高2,奇数为1

问最短天数使所有树都一样高

统计需要在奇数天浇和偶数天的次数,再根据数量判断,可以把长高2拆分成在奇数天浇两天

需要注意的是最后的高度不一定是树高度的最大值,有可能是+1,因为这样可以改变奇偶浇的次数,如果奇数过多的话只能隔一天浇一次,而把部分奇数变为偶数可以穿插在奇数天中,有可能使天数变短

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define AC return 0;
const int MAXN=3e5+7;
int h[MAXN],Max=0,n,ans;
void check(int a){
    int o=0,e=0;
    for(int i=1;i<=n;i++){
        o+=(a-h[i])&1;e+=(a-h[i])/2;//统计次数
    }
    if(o==e||o==e+1)ans=min(ans,o+e);//如果刚好一一配对或者奇数天多一个直接加
    else if(o>e)ans=min(ans,2*e+1+(o-e-1)*2);//奇数天多,先一一配对后面一次奇数操作算两天
    else{
        if((e-o)%3!=2)ans=min(ans,2*o+(e-o)/3*4+(e-o)%3*2);//将三次偶数天的操作拆分为1212
        else ans=min(ans,2*o+(e-o)/3*4+3);//还剩两次偶数天操作拆分为121
        
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        Max=0;
        for(int i=1;i<=n;i++){
            cin>>h[i];
            Max=max(Max,h[i]);
        }
        ans=Max*n*2;
        check(Max);
        check(Max+1);
        cout<<ans<<endl;
    }
    AC
}

D. Progressions Covering

被Hack了很难受orz

题意:给一个长度为n的数组b,和一个初始化为0的a数组。给出一种操作选取长度为k的区间从左到右每个数加分别加1,2,3...k

问最少操作次数使a数组每个位置的值大于等于b

考虑贪心。对于一个1-(k+1)的区间我们先对2-(k+1)做操作使k+1位置的数满足条件再对1-k做操作肯定比反过来次数要少,所以从后往前去贪心是可行的。然后对于每个位置用k去加一定是最快的

#include<bits/stdc++.h>
using namespace std;
#define AC return 0;
#define int long long
const int MAXN=3e5+7;
int a[MAXN],b[MAXN];
signed main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>b[i];
    int ans=0,cnt=0,add=0;
    for(int i=n;i>=1;i--){
        add-=cnt;//每次前面一个数都比后一个小1,一共有cnt操作作用在这两个数上
        if(i<=n-k)cnt-=a[i+k];//对于前一个数来说i+k的操作已经影响不到了所以减去
        int t=min(i,k);//对于前k个点最大只能加i
        if(add<b[i]){
            int num=(b[i]-add-1)/t+1;
            a[i]=num;//每个点的操作次数
            ans+=num;
            cnt+=num;//长度为k区间内的操作次数总和
            add+=num*t;
        }
    }
    cout<<ans<<endl;
}

如有问题劳烦指正

edu场常常被教育c题也是没初始化领到两个wa

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值