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

**Codeforces Round #665 (Div. 2)AD problem solution**
//Written in the rating value 2075/2184
//The question just made up in the afternoon, you must practice three before the 28th, and the competition during this time should be pigeons Up

Contest link: https://codeforces.com/contest/1401 Question
A
Simple thinking

The question means that there is a point A located at (n,0) on the x-axis. Now given a value k, you need to find a point B located at (m,0) satisfying m<=n, making the origin (0,0) The absolute value of the difference between the distance to B and the distance from A to B is equal to k. (N, m, k are all integers)
If such a point cannot be found, we can perform any number of operations on point A, and we can increase or decrease the value of n by 1.
Now you need to output the minimum number of operations so that we can find the point B that meets the requirements.

First, when n=k, we can choose point B as (0, 0). In this case, the length of OB is 0, the length of AB is n=k, the difference between the two distances is k to meet the requirements, and the number of operations is required Is 0.

If n<k, since the sum of the lengths of OB and AB is equal to n, it means that the difference between the two lengths is the largest and cannot be equal to k. We need not to increase the operation of n, and move closer to the situation where n=k. The required number of operations is kn times.

If n>k, it does not mean that no operation is necessary at this time. Also need to consider the parity of n and k. Assuming that the length of OB is L1, the length of AB is L2, and L1>L2, since n, m, and k must all be integers, the lengths of L1 and L2 are also integers.
Given that L1+L2=n, L1-L2=k, we get L1=L2+k
to get 2 × \times× L2=nk, which means that nk must be an even number.
Therefore, when nk is not an integer, we also need to perform a +1 operation on n.

#include<bits/stdc++.h>
#define ll long long
#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--)
    {
    
    
        ll n,k;
        cin>>n>>k;
        if(k<n) cout<<(n-k)%2<<endl;
        else cout<<k-n<<endl;
    }
}

Question B
Classification, greedy, simple thinking

Now there are two series containing only 0, 1, 2, and the length of the two series is equal.
The first sequence has a1 with 0, b1 with 1, and c1 with 2.
The second sequence has a2 0s, b2 1s, and c2 2s.

You now need to match the two columns of these two numbers,
the first number of selected row number is provided x, the second column the number of selected numbers of y
when x = y, the answer to the accumulation 0
when When x>y, add x × \times× y to the answer
When x<y, accumulate -x× \times× y to the answer

Now you need to output the maximum possible final answer.

In this question, there are only three numbers of 0, 1, and 2 in each sequence, and there is 0. The final calculation is multiplication. We directly discuss the following 9 situations and it is easy to find that
only when x=2, y=1, there will be a positive increase in the final answer, and
only when x=1, y=2, there will be a negative increase in the final answer , In
other cases, the increase in the answer is 0.

The two options of positive increase and negative increase are not in conflict. We can directly choose the positive increase with the most logarithms and the negative increase with the least logarithm.

The most logarithmic x=2, y=1 we can increase is the minimum of the number of 2 in the first series and the number of 1 in the second series.
After that, we hope that the logarithms of x=1 and y=2 are as few as possible, so we let the 2 in the second series be paired with 0 and 2 in the second series as much as possible, and the rest can only be matched with 1 pairing, in this case the minimum number of pairs.

#include<bits/stdc++.h>
#define ll long long
#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--)
    {
    
    
        ll a1,b1,c1,a2,b2,c2;
        cin>>a1>>b1>>c1>>a2>>b2>>c2;
        ll ans=0;
        ll temp=min(c1,b2);//考虑我们增加的2*1的对数最多有多少
        ans+=temp*2;c1-=temp;//累加到答案上,并且减去使用掉的第一个数列中的2的个数
        temp=max(0ll,c2-c1-a1);//考虑减少的1*2的对数最少有多少
        //我们尽可能让第二个数列的2与第一个数列的2或者0配对,剩下的无可奈何只能与1配对
        //这里要和0取个max,因为c2-c1-a1可能为负数。
        ans-=2*temp;
        cout<<ans<<endl;
    }
}

Question C
sort, overall thinking

Given a sequence of length n, where the smallest number is Min, you can select two numbers x and y with different subscripts in this sequence to satisfy gcd(x,y)=Min, exchange these two numbers position.
Now ask you if you can make the sequence of numbers sorted from small to large after any number of the above operations.

First of all, we must realize that in the original series, the value cannot divide Min , which means that the factor does not contain Min at all, so the gcd of it and other numbers must not be Min, so its position cannot be changed .

Then, in the original sequence, excluding the numbers that cannot integer Min, and the remaining numbers that can divide Min, to what extent can we sort them through the operation given in the question?
There must be a number in the sequence equal to Min Yes, Min and any gcd that can divide it must be equal to Min, which means that Min can be exchanged with any other remaining numbers .
Once a number satisfies the above-mentioned exchange position with any other position number, we can use this number to perform a similar insertion sorting process to sort the entire series.

That is to say, the numbers that cannot divide Min by the value, we cannot change their position, but the numbers that can divide Min, we can sort them from smallest to largest.

Therefore, we directly sort the original number sequence. Note that when the values ​​are equal, we must sort from small to large subscript, because the numbers that cannot divide Min may be equal in value, and their positions cannot be changed, that is, the order in the original sequence Should be retained. Therefore, we cannot directly use unstable quicksort. Check if the numbers that cannot be divided into Min are the same as the original position index after sorting . If they are different, it means that they cannot be constructed.

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

struct Node
{
    
    
    ll data,tar;
};

ll n,Min;//Min为数列中的最小值
vector<Node>node;

bool cmp(Node a,Node b)//数值为第一排序关键字,数值相等时按照原下标从小到大排序
//即一个稳定的快速排序
{
    
    
    if(a.data!=b.data) return a.data<b.data;
    else return a.tar<b.tar;
}

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n;
        node.resize(n);
        Min=llINF;
        for(ll i=0;i<n;i++)
        {
    
    
            cin>>node[i].data;
            node[i].tar=i;
            Min=min(node[i].data,Min);
        }
        sort(node.begin(),node.end(),cmp);
        bool flag=1;
        for(ll i=0;i<n;i++)
        {
    
    
            if(node[i].data%Min&&i!=node[i].tar) flag=0;
            //如果当前的数值无法整除Min那代表它是无法被交换位置的
            //如果在稳定排序后的位置与其原位置不同,那么代表我们是无法得到稳定排序后的数列的
        }
        if(flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        node.clear();
    }
}

Question D
Greedy, simple graph conclusion

A given tree has n nodes and n-1 edges. Now you need to give a value to each edge, and the value corresponding to the n-1 edges needs to be multiplied by the given number k. Since k may be very large, the input data of the question is the result of k decomposition of prime factors.

Now it is necessary to accumulate the sum of the values ​​of the edges of the simple path between any two points. The final result should be as large as possible, and the number of 1 should be as small as possible when constructing a value for each edge.

The first thing we need to think about is how many times has it been accumulated in the final result for each edge on this tree.
Take the picture of the first sample of the title as an example:
Insert picture description here
In the picture above, the edge in the middle has two points 1 and 2 on the left and two points 3 and 4 on the right. A total of 2 × \times is calculated for this edge× 2=4 times. That is, the number of nodes on the left is multiplied by the number of nodes on the right, because the simple path from the point on the left to the point on the right must pass through the current edge. The simple path from the point on the left to the point on the left or the point on the right to the point on the right does not need to go through the current side.

We can calculate the number of child nodes of each node through the dfs starting from the root node, and then calculate how many times each edge is calculated in the final result.

Then is the process of how to construct the value of these n-1 edges.
The title requires that the numerical product of these n-1 edges is equal to k, so the result of their decomposition of prime factors must be the same as k.
When the number of prime factors obtained by k decomposing prime factors is m<=n-1, we directly adopt the greedy process, and match the number of prime factors with the number of appearances of the edge in the final result. The lack of m<n-1 is filled with 1, and any value of 1 times any value is equal to the original value.
When m>n-1. Using the same greedy strategy, we multiply the largest m-(n-1)+1 prime factors and place them on the side with the largest number of occurrences. (The correctness of this greed can be proved by contradiction). Then take the same greedy matching process as in the previous case.

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

ll n,m,start;
vector<vector<ll>>to(1e5+7);//存边
vector<ll>sun;//sun[i]记录结点i包括自己有几个子节点,用于计算边被计算几次
deque<ll>k;//k分解质因子后得到的数列
deque<ll>edgenum;//存储每条边各自会被计算多少次累加到结果上,排序后用于贪心过程

void dfs(ll now,ll pre)//now为当前所在节点,pre为上一个节点
{
    
    
    for(ll i=0;i<to[now].size();i++)
    {
    
    
        if(to[now][i]!=pre)//不往回走
        {
    
    
            dfs(to[now][i],now);
            sun[now]+=sun[to[now][i]];//累加子树的子节点数当前节点上
        }
    }
    sun[now]++;//自身也算做一个子节点
    if(now!=start) edgenum.push_back((n-sun[now])*sun[now]);
    //对于now到pre的这条边来说,sun[now]为这条边“下面”的子节点数,那么n-sun[now]即为这条边"上面"的子节点数
}

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n;
        for(ll i=1;i<=n;i++)
            to[i].clear();
        for(ll i=1;i<n;i++)
        {
    
    
            ll u,v;
            cin>>u>>v;
            to[u].push_back(v);
            to[v].push_back(u);
        }
        cin>>m;
        k.resize(m);
        for(ll i=0;i<m;i++) cin>>k[i];
        sort(k.begin(),k.end());//排序用于贪心
        for(ll i=1;i<=n;i++)//找一个出度为0的点,作为树的根进行dfs
            if(to[i].size()==1) start=i;
        sun.clear();sun.resize(n+1,0);
        edgenum.clear();
        dfs(start,-1);//dfs计算每条边会被计算几次到答案上,也就是每条边的权值
        sort(edgenum.begin(),edgenum.end());//排序用于贪心
        while(m>edgenum.size())//m为k数组的大小,如果m的个数大于边的个数,我们要贪心使得权值最大的边对应最大的乘积
        //不断累乘最大的值给第二大的数,缩小数组大小即可
        {
    
    
            k[m-2]=(k[m-2]*k[m-1]%mod);
            k.pop_back();
            m--;
        }
        while(m<edgenum.size())//再考虑m个数小于边的个数时,我们需要在剩下的边补1
        {
    
    
            k.push_front(1);
            m++;
        }
        ll ans=0;
        for(ll i=0;i<m;i++)//贪心过程,小的值配权值小的边,不断累加到答案上
        {
    
    
            ans=(ans+edgenum[i]%mod*k[i]%mod)%mod;
        }
        cout<<ans<<endl;
    }
}

Guess you like

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