Educational Codeforces Round 95 (Rated for Div. 2)A-D题解

Educational Codeforces Round 95 (Rated for Div. 2) AD problem solution
// written in rating value 1987/2184
//This unrated...very fascinating one.
//After reading the question surface of A, my heart: "Isn't this a stupid question?" Look at the example: "?????". "Is it because I misread the meaning of the question??", I went back and read the meaning of the question twice, and then the official began to make an announcement. The sample and evaluation data of A were modified at about 11 minutes.
//13 minutes passed A, and another 13 minutes passed B and C. After reading half of D’s question, the official issued an announcement saying that it was unrated, and the speed of light flew back to the bedroom before the entrance...
//D’s conclusion and The idea of ​​using set and priority queue has been derived, but some function operations of set are not familiar, take this opportunity to learn a wave

Question A
Water question

The question means that you have 1 stick at the beginning, and you can make 1 torch with 1 stick and 1 part of fuel. Now you want to make k torches. You can trade any number of times, and you can choose the following two trading methods for each transaction:
1. Exchange 1 stick for x sticks
2. Use y sticks for 1 piece of fuel
Now ask you at least a few transactions to make it k torches.

To make k torches requires at least k sticks and k fuel.
First of all, we don’t have fuel on hand, and fuel can only be obtained by swapping with wooden sticks, so k parts of fuel need to be carried out at least k times for the second transaction with k × \times× y sticks are obtained in exchange, a total of at least k× \times× y+k sticks. The first trading method can be seen as adding x-1 sticks per transaction. Therefore, the minimum number of transactions required for the first type is (k× \times× y+k)/(x-1) is rounded up, plus the k times required for the second type of transaction is the answer.

#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--)
    {
    
    
        ll x,y,k;
        cin>>x>>y>>k;
        ll need=k*y+k;
        ll ans=(need-1)/(x-1)+k;
        if((need-1)%(x-1)) ans++;
        cout<<ans<<endl;
    }
}

Question B
Greedy

The question means that given a number sequence of length n, some positions are locked, we cannot change the positions of the numbers in these positions, and the other positions are not locked, we can exchange the positions of the numbers in these positions at will.
Now I hope you can rearrange the numbers in the unlocked positions of this sequence so that the prefix of this sequence and the largest subscript of the negative number in the array are the smallest. Output any construction method.

Here the maximum subscript of the negative number in the prefix and the array is the smallest, so for the prefix sum of a certain fixed subscript, we must hope that the number constructed in the previous section is as large as possible. This greed is the same for each fixed subscript. Therefore, we can directly rearrange all the numbers in the unlocked position in descending order.

#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;

vector<int>num;
int n;
int cas[107];

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n;
        num.clear();
        num.resize(n);
        deque<int>Q;//用于存储不锁定位置上的数字,排序后进行后续构造操作
        for(int i=0;i<n;i++) cin>>num[i];
        for(int i=0;i<n;i++)
        {
    
    
            cin>>cas[i];
            if(!cas[i]) Q.push_back(num[i]);
        }
        sort(Q.begin(),Q.end());
        for(int i=0;i<n;i++)
        {
    
    
            if(!cas[i])//对不锁定位置,我们依次按照从大到小的顺序把所有数字放进去。
            {
    
    
                num[i]=Q[Q.size()-1];
                Q.pop_back();
            }
        }
        for(int i=0;i<n;i++) cout<<num[i]<<' ';
        cout<<endl;
    }
}

Question C
Greedy, holistic thinking

The title means that there are n bosses to be killed in turn, one part is simple boss and part is difficult boss. You and your friend kill the boss alternately (friend first).
You can choose to kill 1 or 2 bosses each time, but your friend cannot kill the difficult boss. When he needs to kill the difficult boss, he needs to use it. Only one item can be killed. Now you need to find the best strategy for you and your friends, the minimum number of times your friends use props.

Since the friend takes the first step, the first boss must be killed by the friend. If the first is the difficult boss, the friend must use the item once. The questions after that can be seen as first hand.
For x consecutive difficult bosses, if you are the first to take the initiative, you will adopt a greedy strategy. You will kill 2 each time, and your friends will kill 1 each time. Then you need to kill these x bosses. The minimum number of items is x/3.
These n-1 (except the first) boss can be regarded as a number of consecutive difficult bosses. There are 1 or more simple bosses between them. Can we use some strategy to make each consecutive difficult boss all Did you start killing by yourself?
Note that if you and your friends can only kill 1 boss, they will be fixed as friends can only kill odd-numbered bosses, and you can only kill even-numbered bosses, but now you and your friends can choose to kill 2 bosses, once you choose to kill 2 bosses, the parity index corresponding to yourself and your friend will be exchanged. Through simple bosses between consecutive difficult bosses in adjacent segments, we can choose to kill 2 bosses and exchange the odd and even subscripts of two people to ensure that the next difficult bosses are killed by ourselves.

It can be concluded that the minimum number of props required is n-1 bosses except the first boss. The number of each successive difficult boss is divided by 3 and then accumulated. If the first boss is difficult, add 1 more. .

#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=2e5+7;

ll num[maxn];
ll n;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n;
        for(ll i=0;i<n;i++) cin>>num[i];
        ll ans=0;
        if(num[0]) ans++;//由于朋友是先手,因此第一个boss如果就是困难的那就必须要使用一次道具
        ll temp=0;
        for(ll i=1;i<n;i++)
        {
    
    
            while(i<n&&num[i]==1)//统计连续的困难boss有多少个
            {
    
    
                temp++;
                i++;
            }
            ans+=temp/3;//除3加到答案上并置零
            temp=0;
        }
        cout<<ans<<endl;
    }
}

Question D
Greedy, set and priority queue maintain the maximum length of the line segment between adjacent points

The question means that there are garbage at a number of integer points on an x-axis. Now you need to gather this garbage to no more than 2 points. You can select a subscript x for each operation, and move all garbage at position x to position x-1 or x+1. You need to output the minimum number of operations. And this question has q operations to change the initial garbage situation. Each change will add or delete a garbage. You need to output the minimum number of operations after each change.

Let me start with a conclusion. If we gather all the rubbish at one point, the optimal operation is the distance between the rightmost position of the rubbish and the leftmost position. Because we arbitrarily choose a point on this line segment as our final gathering point, the left part moves from the far left to the right, and the right part moves from the far right to the left. This is the optimal solution. Equal to the length of the line segment. If we choose the final gathering point at a position outside the line segment, draw it on our own manuscript paper to know that more operations are needed (the basics of high school mathematics will not be covered).
Now we can gather on two points, so that means we can remove the original line segment from the line segment between a pair of adjacent garbage, and the remaining two line segments are aggregated separately, then we only need to make the deleted one The maximum length of the line segment is the optimal solution.

In this way, the problem is transformed into how to maintain the maximum value of the adjacent line segment length of a dynamic point, which is realized by using set and priority queue here. The way of thinking here is that we only need to pay attention to the maximum value in the line segment, so we can use the priority queue to achieve it, but the priority queue does not support the deletion of any value. We only need to open another priority queue to save the length of the line segment to be deleted. can.
In the operation of inserting and deleting points in the original picture, we only need to know whether there is garbage on the left and right sides of the newly added points in the original picture, and where their positions are, we can know which line segments need to be deleted and added.

See the code for specific implementation.

#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;

int n,q;
set<ll>S;//集合S用于存储当前有哪些位置上有垃圾,用于计算实现下面两个优先队列的当前线段和待删除线段
priority_queue<ll>length_now,length_delete;
//两个优先队列,now存储当前的图上所有的相邻点之间的线段长度,delete为插入和删除点过程中产生的待删除线段

//由于我们只关注所有点的最左侧和最右侧的距离(set可计算),以及相邻点之间的线段长度中的最大值(优先队列的top()可以获得)

void insert(ll x)//增加点操作
{
    
    
    if(S.size())//增加点可能会造成线段的增加和减少
    {
    
    
        auto now=S.lower_bound(x);//用lower_bound找到集合S中大于x的第一个位置
        if(now==S.begin()) length_now.push(*now-x);//如果大于x的第一个位置就是最小的点了,那加入的点是在目前的最左侧,只增加了*now-x这一条线段
        else//如果大于x的第一个位置不是最小的点
        {
    
    
            if(now==S.end())//如果大于x的第一个位置是集合的末尾,代表加入的点在最右侧,对now--操作变成之前最大点的位置,只增加了x-*now这一条线段
            {
    
    
                now--;
                length_now.push(x-*now);
            }
            else//如果不是末尾,则代表新加入的点是在两个点的中间
            {
    
    
                ll temp=*now;//用temp临时记录右侧点的值,再对now--变为左侧点的位置
                now--;
                length_now.push(temp-x);//新增加了两条线段,分别与左右侧相邻点构成
                length_now.push(x-*now);
                length_delete.push(temp-*now);//原本左右侧相邻点构成的线段被删除
            }
        }
    }
    S.insert(x);
}

void erase(ll x)//同insert操作的思路
{
    
    
    S.erase(x);
    if(S.size())
    {
    
    
        auto now=S.lower_bound(x);
        if(now==S.begin()) length_delete.push(*now-x);
        else
        {
    
    
            if(now!=S.end())
            {
    
    
                ll temp=*now;
                now--;
                length_now.push(temp-*now);
                length_delete.push(temp-x);
                length_delete.push(x-*now);
            }
            else
            {
    
    
                now--;
                length_delete.push(x-*now);
            }
        }
    }
}

void out()
{
    
    
    if(S.size()==0) cout<<0<<endl;//这里要特判一下集合S是否为空,否则下面的rbegin()-begin()的操作会出错
    else
    {
    
    
        while(length_delete.size()&&length_delete.top()==length_now.top())//我们只关注所有线段中最大的值,因此用优先队列存储即可
        {
    
    //把待删除的最大线段依次删去即可
            length_delete.pop();
            length_now.pop();
        }
        ll ans=*S.rbegin()-*S.begin();
        if(length_now.size()) cout<<ans-length_now.top()<<endl;
        else cout<<0<<endl;
    }
}

int32_t main()
{
    
    
    IOS;
    cin>>n>>q;
    for(ll i=0;i<n;i++)
    {
    
    
        ll x;
        cin>>x;
        insert(x);
    }
    out();
    for(ll i=0;i<q;i++)
    {
    
    
        ll ope,x;
        cin>>ope>>x;
        if(ope) insert(x);
        else erase(x);
        out();
    }
}

Guess you like

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