codeforces 成长之路 #668 div2 题解

比赛链接

https://codeforces.ml/contest/1405

A. Permutation Forgery

题目大意

给你一个1~n的排列,然后用数组中每两个相邻元素的和构成一个新的数组,对其进行排序得到数组c。让你找出一个与给出的排列不同的排列,让其进行以上相同操作后得到的数组c2与c相同。

解题思路

首先思考要让排序过后的两个数组c和c2相等,那么就是让两个数组中的元素相等。而c中每个元素是给定排列的相邻元素之和,则我们只要逆转给定排序,即可满足条件。

AC代码

#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
int a[MAXN];
void solve()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=n;i>=1;i--)
        cout<<a[i]<<' ';
    cout<<endl;
}
int main()
{
    int T;cin>>T;
    while(T--)
        solve();
 }
 

B. Array Cancellation

题目大意

给定一个数组a,且所有元素和为0。每次操作可以选定一组(i,j)增加 a[i]的值,同时 a[j] 减去相同大小的值,最后让所有元素的值都为0。若 i < j 则无开销,反之开销为增减的值大小。问最小开销是多少。

解题思路

题目中给出 i < j 的时候增减是没有开销的,因此贪心选择 尽量使得每个每个靠前的正数能给把数值分配给他后面的负数。当没法分配的时候残余的值就不得不往前分配,便是最小开销。

AC代码

#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
long long a[MAXN];
void solve()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    long long premix=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>0)
            premix+=a[i];
        if(a[i]<0&&premix>0)
            premix=max(0LL,premix+a[i]);
    }
    cout<<premix<<endl;
}
int main()
{
    int T;cin>>T;
    while(T--)
        solve();
}

C. Balanced Bitstring

题目大意

给你一个01串 s 和一个偶数k,01串内的?可以变成0或者1,问你是否可以让该串每个长度为k的子串里0和1的数量相等。

解题思路

通过观察发现,s[i] 和 s[i+k] 应该是相同的 因为当区间从s[i]-s[i+k-1]转移到 s[i+1]-s[i+k] 的时候,我们减去了s[i],所以要让区间里的0和1仍然平衡,则加上的s[i+k]必然等于s[i]。我们只需要判断能否满足这个条件即可。

AC代码

#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
long long a[MAXN];
void solve()
{
    int n,k;cin>>n>>k;int a=0,b=0,c=0;
    string s;cin>>s;int flag=1;
    for(int i=k;i<s.size();i++)
    {
        if(s[i]!=s[i%k])
        {
            if(s[i%k]=='?')
                s[i%k]=s[i];
            else if(s[i%k]!='?'&&s[i]!='?')
                goto Tag;
        }
    }
    for(int i=0;i<k;i++)
    {
        if(s[i]=='1')
            a++;
        else if(s[i]=='0')
            b++;
        else
            c++;
    }
    if(abs(a-b)>c)
        goto Tag;
    else
        cout<<"YES"<<endl;
    return;
    Tag:
        cout<<"NO"<<endl;
}
int main()
{
    int T;cin>>T;
    while(T--)
        solve();
}

D. Tree Tag

题目大意

Alice和Bob都在一棵树上,起始点为a和b,且Alice要去抓Bob。Alice每步可以走最多da步,Bob每次最多可以走db步,且Alice和Bob轮流走,问Alice能不能抓住Bob。(Alice走完一次落在Bob所在的节点上)

解题思路

先观察数据,我们发现第二个数据是一条链,而Bob可以在Alice的左右两边反复横跳,让Alice无法追上。于是我们想,是不是能在树上找到一条这样的链,达到这样的效果。由于树的直径是树上最长的一条链,我们可以求出树的直径结合Alice和Bob可以跳的步数判断是否可以达成如上效果。应满足的条件有:
da*2 < min(db, 直径) (Bob可以跳的距离足够长,以至于能在Alice的左右两边左右横跳而不被追上。
dist(a,b)>da (由于第一轮是Alice,如果b和a的距离小于da,则Alice可以直接抓住Bob)

AC代码

#include<bits/stdc++.h>
#define MAXN 3000005
using namespace std;
struct EDGE
{
    int to,next;
}edge[MAXN];int ptr;
int head[MAXN];
void add_edge(int from,int to)
{
    edge[++ptr].to=to;
    edge[ptr].next=head[from];
    head[from]=ptr;
}
//求树的深度
int depth[MAXN];
void dfs(int now,int f)
{
    depth[now]=depth[f]+1;
    for(int p=head[now];p;p=edge[p].next)
    {
        int to=edge[p].to;
        if(to!=f)dfs(to,now);
    }
}
void init(int n)
{
    ptr=0;
    for(int i=1;i<=n;i++)
        head[i]=edge[i].to=edge[i].next=depth[i]=0;
}
//求a和b的距离
int dist(int a,int b)  
{
    dfs(a,0);
    return depth[b]-1;
}
void solve()
{
    int n,a,b,da,db;cin>>n>>a>>b>>da>>db;
    init(n);
    for(int i=1;i<n;i++)
    {
        int u,v;cin>>u>>v;
        add_edge(u,v);
        add_edge(v,u);
    }
    //求树的直径
    dfs(1,0);int maxx=0,root=0;
    for(int i=1;i<=n;i++)
        if(depth[i]>maxx)
            maxx=depth[i],root=i;
    dfs(root,0);maxx=0; 
    for(int i=1;i<=n;i++)
        maxx=max(maxx,depth[i]); //maxx是树的直径+1
    if(maxx-1>2*da&&da*2<db&&dist(a,b)>da)
        cout<<"Bob"<<endl;
    else
        cout<<"Alice"<<endl;
}
int main()
{
    int T;cin>>T;
    while(T--)
        solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值