Codeforces Round #668 (Div. 2) AD problem solution

Codeforces Round #668 (Div. 2) AD problem solution
// written in the rating value 2033/2184
//Recently took a small vacation and recently had a lot of things at home, it was delayed until now to make up for this problem solution.//Go
back to school today Up

Contest link: https://codeforces.ml/contest/1405 Question
A
Simple thinking water question

The question means that for an arrangement of length n, we define a special operation fingerprintf operation to calculate the sum of each two adjacent numbers in this arrangement of length n (obviously such an operation will get n-1 numbers ), the result of sort.
Now given a permutation a, you need to construct a permutation b with the same length as a, so that the two permutations have the same result under the fingerprintf operation.

We noticed that the final result is sorted, which means that the order of numbers is irrelevant, as long as the numbers of the same value appear the same number of times.
Then we can directly output the original arrangement in reverse... No explanation

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        vector<int>num(n);
        for(int i=n-1;i>=0;i--) cin>>num[i];
        for(int i=0;i<n;i++)
        {
    
    
            if(i) cout<<' ';
            cout<<num[i];
        }
        cout<<endl;
    }
}

Question B
Simple thinking, execution, greedy

The question means that there is a sequence num[] of length n, and the sum of all numbers in the sequence is 0.
Now your goal is to make every number in the sequence become 0 after performing several operations.
For each operation, you can choose two subscripts i and j, perform -1 operation on num[i] and perform +1 operation on num[j]. If i<j, then this operation is costless, if i>j then This operation requires one coin.
Now you need to find the minimum number of coins to be consumed.

Let’s think about it with greed. We start from the left and look to the right. The positive part that appears can be used with the negative number on the right side of the current position without consumption, and the negative part can only be used with the integer on the left side of the current position. Consume operation.
For the idea of ​​using no-consumption operations as much as possible, the more negative the position is, the more disadvantageous it is. Therefore, we can directly adopt a greedy strategy, use a temp to record how many positive numbers appear on the left side of the current position, and perform a costless offset operation with negative numbers. In this process, if temp<0 appears, it means that the negative number at the current position has no positive number on the left side and can be offset without consumption. It must be offset with the positive number on the right side to offset the consumption of coins, and then directly accumulate The absolute value of temp reaches the number of the last answer and temp is set to zero.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        vector<ll>num(n);
        for(auto &x:num) cin>>x;
        ll ans=0;
        ll temp=0;//temp记录我们当前位置左侧还有多少的正数可用
        for(int i=0;i<n;i++)
        {
    
    
            temp+=num[i];//下面的if运算保证了temp一定不是负数
            //temp与当前位置上的数字进行加法运算,如果num[i]是负数则正是题意中无消耗的操作
            if(temp<0)//如果出现了无法被无消耗操作除去的负数部分,则必然要与后面的正数进行有消耗的操作
                //此处累加temp的绝对值到答案上,并清零
            {
    
    
                ans-=temp;
                temp=0;
            }
        }
        if(temp<0) ans-=temp;
        cout<<ans<<endl;
    }
}

Question C
Simple conclusion, greedy, implementation

The question means that given a string s of length n, the string s only contains three characters: '0', '1', and'?'. And given an even number k, now I ask whether it is possible to replace the character'?' in the string s with 0 or 1 to satisfy all continuous substrings of length k in the string s, and 0 and 1 in the substring The numbers are equal, that is, all are k/2.

First push a small conclusion,

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=3e5+7;

char firt[maxn];//firt[x]记录字符串s的下标i中,所有满足i%k=x的i,对应的字符是否相同,初始为'?'
//上述条件的所有字符相同,是字符串s的所有长度为k的子串中,0和1出现次数相同的充要条件
//这个条件是题目限定的所有长度为k子串中,0出现的次数均等于1出现的次数这个条件的弱化版本,为前置条件
int n,k;
string s;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n>>k>>s;
        for(int i=0;i<k;i++) firt[i]='?';
        bool flag=1;
        for(int i=0;i<n;i++)
        {
    
    
            if(firt[i%k]=='?') firt[i%k]=s[i];//如果当前firt[i]仍然为'?"代表没有出现固定的0或者1
            else if(s[i]!='?'&&firt[i%k]!=s[i]) flag=0;
            //如果firt[i%k]已经是0或者1了,而s[i]不为'?'且不与firt[i%k]相同的话则出现冲突,直接flag置零
        }
        int sum0=0,sum1=0;
        for(int i=0;i<k;i++)//再检测,每段长度为k的子串中,目前已经确定必须有的0和1各自有多少个
        {
    
    
            if(firt[i]=='0') sum0++;
            if(firt[i]=='1') sum1++;
        }
        if(sum0>k/2||sum1>k/2) flag=0;//如果0或者1出现的个数超过了长度k的一半,同样是不满足条件的
        //此处与firt数组实现的条件一同,构成了题目要求的条件
        if(flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

Question D
Game on the tree

The question means that on a number with n nodes, Alice and Bob are at points a and b, respectively. Starting from Alice, they hand in the questions and start to move. If Alice and Bob are in the same position at a certain moment, then Alice wins, otherwise Bob wins. Alice can move the farthest to a point away from the current position da each time, and Bob can move the farthest to a point away from the current position db each time. Now I hope you can judge which of the two wins.

Regarding the game, we also start from the most basic situation.

First of all, how can Alice win the next move, that is, when the distance between the two positions is dis_ab<=da, she can walk directly to Bob's position to win in one move.

After that, let’s not think about being on a tree, but on a straight line with L nodes. If 2 × \timesIf × da>=L-1, Alice can first choose to walk to the middle position of this line, and Alice can walk to any position on this line in the next move. At this point, Alice can win no matter where Bob is.
Next, consider the tree. If the tree is a tree, you can also see a number of overlapping lines. The diameter x of the tree is the length of the longest line, and only 2× \timesis required× da>=x, Alice can adopt the above strategy to ensure she wins.

Then if 2 × \times× da<x, Alice cannot win through the above strategy.
Similarly, we are still thinking about it on a straight line. For Bob, if he stays on the same side of Alice on this straight line, Alice can continuously reduce the length of the side and keep approaching, and finally win. Therefore, Bob must move from Alice's left to right (or right to left), and ensure that he will not be caught up by Alice once after moving.
The distance between Bob and Alice cannot be less than or equal to da, so we can get when 2× \timesWhen × da>=db, Bob cannot move from one side of Alice to the other while ensuring his safety, and Alice must win.

Then 2 × \timesWhen × da<db, Bob can safely move from side to side, and Bob can ensure that he is undefeated.

Since then, all cases have been derived.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=1e5+7;

ll n,a,b,da,db,dis_ab;//dis_ab记录在树上a和b两点之间的距离
ll dis[maxn];//dis[i]记录每次dfs过程中,i点距离起点的距离

struct Edge
{
    
    
    ll to,next;
}edge[maxn<<1];

ll head[maxn],tot;

void init()
{
    
    
    for(ll i=1;i<=n;i++) head[i]=-1;
    tot=0;
}

void add(ll u,ll v)
{
    
    
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
//前向星存图

void dfs(ll now,ll pre,ll deep)
{
    
    
    dis[now]=deep;
    for(ll i=head[now];i!=-1;i=edge[i].next)
    {
    
    
        ll to=edge[i].to;
        if(to!=pre)
        {
    
    
            dfs(to,now,deep+1);
        }
    }
}


int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n>>a>>b>>da>>db;
        init();
        for(ll i=1;i<n;i++)
        {
    
    
            ll u,v;
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }

        //两次dfs得到树的直径,第一次dfs的起点可以任意选择,第二次dfs的起点选择第一次dfs过程中距离最远的点
        //两次dfs得到的两个距离最远的点就是树的直径的两个端点,第二次dfs结束后dis[]数组中的最大值就是树的直径大小
        //由于第一次dfs的起点可以任意选择,因此我们选择a为起点,顺带计算出a和b两点间的距离
        dfs(a,-1,0);
        ll tar=1;
        for(ll i=2;i<=n;i++)
            if(dis[i]>dis[tar]) tar=i;

        dis_ab=dis[b];
        dfs(tar,-1,0);
        tar=1;
        for(ll i=2;i<=n;i++)
            if(dis[i]>dis[tar]) tar=i;

        if(dis_ab<=da||2*da>=dis[tar]||da*2>=db) cout<<"Alice"<<endl;
        else cout<<"Bob"<<endl;
    }
}

Guess you like

Origin blog.csdn.net/StandNotAlone/article/details/108474095