Codeforces 成长之路 Educational Codeforces Round 100 (Rated for Div. 2) 题解

@[TOC](Codeforces 成长之路 Educational Codeforces Round 100 (Rated for Div. 2) 题解)

比赛地址

https://codeforces.ml/contest/1463

A. Dungeon

题目大意

给你a、b、c三个数,你每次操作可以选择其中一个数减去1,每逢7的倍数次操作,三个数都减去1。问是否可以在某一轮三个数同时变成零。

解题思路

要让最后一次是三个数同时减1,那么总次数一定是7的倍数,每一轮7次一共减去的值是9,先判断三个数的总和是不是9的倍数,如果是9的倍数,算出需要几轮7次操作。注意三个数中最小的数的值应当大于等于操作7次的数量。

AC代码

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
typedef long long ll;
void solve()
{
    ll a,b,c;cin>>a>>b>>c;
    ll m=min(a,min(b,c));
    if((a+b+c)%9==0&&(a+b+c)/9<=m)
        cout<<"YES"<<endl;
    else
        cout<<"NO"<<endl;
}
int main()
{
   int T;cin>>T;
    while(T--)
        solve();
}

B. Find The Array

题目大意

给你一个数组a,让你构造一个长度相等的数组b,使得:

  1. 2∑i=(1~n) |ai−bi|≤S.
  2. b[i] % b[i+1] == 0 || b[i+1] % b[i] == 0.

解题思路

1可以被任何数整除,我们选择交替输出1和a本身。
先计算出a的奇数位之和与偶数位之和,若奇数位更小,则奇数位全部输出1,偶数位全部输出a本身。偶数位更小同理。

AC代码

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std;
typedef long long ll;
ll a[MAXN];
void solve()
{
    int n;cin>>n;ll sum1=0,sum2=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(i%2==1)
        sum1+=a[i];
        else
        sum2+=a[i];
    }
    int flag;
    if(sum1>=sum2) flag=1;
    else flag=0;
    for(int i=1;i<=n;i++)
    {
        if(i%2==flag)
            cout<<a[i]<<' ';
        else
            cout<<1<<' ';
    }
}
int main()
{
   int T;cin>>T;
    while(T--)
        solve();
}

C. Busy Robot

题目大意

有个机器人,在数轴上移动,你给出 (ti,xi) 的指令,代表指令下达的时间和需要他移动到的位置。收到指令以后机器人会以1的速度移动。如果下达指令时机器人在运动中则忽略当下指令。一个指令 i 是成功的当 ti 到 t(i+1) 的时间 内机器人有出现在 xi 位置过。 现在让你计算成功的指令的数量。

解题思路

模拟,把每个指令时间点机器人的位置记录下来,然后判断目标位置是不是夹在 ti 和 t(i+1) 两个时间点的位置之间,就可以知道 i 指令是否成功。

AC代码

#include<bits/stdc++.h>
#define MAXN 200010
using namespace std;
typedef long long ll;
ll t[MAXN], x[MAXN], pos[MAXN];
ll sign(ll x)
{
    if(x > 0) return 1;
    if(x < 0) return -1;
    return 0;
}
void solve()
{
    ll n;cin>>n;
        for(ll i = 1; i <= n; i ++)  cin>>t[i]>>x[i];
        ll ans=0,qqq=0,endd=0;
        for(ll i = 1; i <= n; i ++)
        {
            if(t[i]>=endd)
            {
                pos[i]=qqq;
                endd=t[i]+abs(x[i]-qqq);
                qqq=x[i];
            }
            else
                pos[i]=pos[i-1]+sign(qqq-pos[i-1])*(t[i]-t[i-1]);
        }
        pos[n+1]=qqq;
        for(ll i=1;i<=n;i++)
        {
            ll l=pos[i],r=pos[i+1];
            if(l >r)
                swap(l, r);
            if(x[i]>=l&&x[i]<=r)
                ans ++;
        }
        cout<<ans<<endl;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
        solve();
}

D. Pairs

题目大意

你可以让 1~2n 之间的数两两结对,且设定一个 x,让其中 x 对中较小数和 n-x 对中的较大值组成所给的 n 个数。问x的数量有多少。

解题思路

为给出的n个数找配对对象。用贪心的方法,则给出的数较小的 x 个应该和其余数较大的 x 个配对,较大的 n-x 个与剩余数的 n-x 配对。只要能成功配对则当前 x 值可行。我们可以通过二分的方式搜出最多可以让多少给出的较小的数找到其配对对象。此外,还需要保证给出的 n-x 个较大数能找到配对对象。同理,用二分搜索找出 n-x 的最大值,即 x 的最小值,就得到了 x 的范围。

AC代码

#include<bits/stdc++.h>
#define MAXN 500005
using namespace std;
typedef long long ll;
int a[MAXN];
bool mark[MAXN];
int n;
bool check_1(int x)
{
    for(int i = x, j = n<<1; i >= 1; i --)
    {
        while(mark[j])
        {
            j --;
            if(j <= a[i]) return 0;
        }
        j --;
    }
    return 1;
}
bool check_2(int x)
{
    for(int i = x+1, j = 1; i <=n; i ++)
    {
        while(mark[j])
        {
            j ++;
            if(j >= a[i]) return 0;
        }
        j ++;
    }
    return 1;
}
void solve()
{
    memset(mark,0,sizeof(mark));
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        mark[a[i]]=1;
    }
    int l=0,r=n;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(check_1(mid))
            l=mid;
        else
            r=mid-1;
    }
    int R=l;
    l=0,r=n;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check_2(mid))
            r=mid;
        else
            l=mid+1;
    }
    cout<<R-r+1<<endl;
}
int main()
{
    int T;cin>>T;
    while(T--)
        solve();
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值