Codeforces Round #673 (Div. 2) AE problem solution

Codeforces Round #673 (Div. 2) AE problem solution

Contest link: https://codeforces.com/contest/1417

Question A
Water, greedy

The question means that given a sequence of length n, and given an upper limit k, each number in the original sequence is between 1 and k, now you can add a number in the current sequence every time you operate To another number, but you can't let the value exceed k, now ask how many times you can operate at most.

Directly choose the one with the smallest value, and add as many other numbers as possible with this smallest value.

#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,k;
        cin>>n>>k;
        int ans=0,tar=0;
        vector<int>num(n);
        for(int i=0;i<n;i++)
        {
    
    
            cin>>num[i];
            if(num[i]<num[tar]) tar=i;
        }
        for(int i=0;i<n;i++)
            if(i!=tar) ans+=(k-num[i])/num[tar];
        cout<<ans<<endl;
    }
} 

Question B
Greedy, structure

The question means that given a sequence of length n, and given a value T, now you are required to divide the original sequence into two sequence, the two sequence of numbers in the same sequence of numbers that add up to T have the least number of subscripts.

Just be greedy. Put the half of T into the first series, and the half larger than T into the second series. The half of T can be divided evenly into less than two series. Because the half less than T can only be added to the half greater than T to be equal to T, you can simply divide them into two parts. The conclusion that is exactly equal to half of the uniform distribution can be calculated on the manuscript paper.

#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 n,T;
        cin>>n>>T;
        bool flag=0;
        vector<bool>color(n);
        for(int i=0;i<n;i++)
        {
    
    
            ll x;
            cin>>x;
            if(x*2==T) {
    
    color[i]=flag;flag=!flag;}
            else if(x*2<T) color[i]=0;
            else color[i]=1;
        }
        for(int i=0;i<n;i++) cout<<color[i]<<' ';
        cout<<endl;
    }
}

C problem
string, small conclusion, simple use of map

Given a sequence of length n, you need to output the pair and the value of k with the value 1-n, the pair and all the continuous subsequences of length k in the sequence, and the smallest number in common. If there is no shared number, -1 is output.

If you think directly from the front, you will find it difficult to think. We can see from a specific value, if this value is used as the smallest common value of a certain length k, the length k needs to be no less than the maximum distance between adjacent positions in all the positions where the value appears in the sequence (note that The leftmost and rightmost side of the sequence shall be specially judged). Using this conclusion, we can use map to get the minimum k corresponding to each value in a for loop. After recording, directly perform 1-n on kfor as the answer, and output the minimum k.

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#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;
        map<int,pair<int,int>>M;//M[i]=pair{j,k},代表值为i的数字最后出现在下标j的位置,值为i的数字之间的最大间隔为k
        for(int i=1;i<=n;i++)
        {
    
    
            int x;
            cin>>x;
            if(M.find(x)==M.end()) M[x]=make_pair(i,i);//数列左侧特判
            else
            {
    
    
                M[x].second=max(M[x].second,i-M[x].first);
                M[x].first=i;
            }
        }
        vector<int>ans(n+1,INF);
        for(auto &x:M)
        {
    
    
            x.second.second=max(x.second.second,n+1-x.second.first);//特判数列右侧
            ans[x.second.second]=min(ans[x.second.second],x.first);
        }
        int now=INF;
        for(int i=1;i<=n;i++)
        {
    
    
            now=min(now,ans[i]);
            if(now==INF) cout<<-1<<' ';
            else cout<<now<<' ';
        }
        cout<<endl;
    }
}

Question D
structure, thinking

The question means that given a sequence of length n, the value of each number is a positive integer between 1 and 1e5, and now you need to make the value of each number in this sequence at most 3n operations equal.
For each operation, you can choose two subscripts i and j, and choose a natural number x between 0 and 1e9, and subtract i × \times from ai× x, add i× \timesto aj× x。

First of all, notice that the sum of the entire sequence has not been changed during the operation. Therefore, the sum of the entire sequence must be constructed by an integer of the sequence length n. Then we noticed that the particularity of the operation here is that we need to multiply the subscript i for the value of the two subscripts. It is easy to think that if the number of subscript 1 is large enough, it can satisfy us in one operation. For the construction of a position, can we first gather all the values ​​of the entire sequence into a1 in some way, and then for all the positions allocated by n? We noticed that if we want to move all the values ​​at the position of aj to a1, the value of aj needs to be divisible by j. Then if the value of aj cannot divide j, we need to add the value from other places to aj.
It is very easy to think of using a1 to add to aj to make aj divide j, and then we will find that...Directly for from 2 to n must complete the operation of clearing a2 to an, because every number in the original sequence It is a positive integer, which means that the sum of the previous n numbers is at least n, which means that the value of aj must be divisible by j.
So our first pass for subscripts 2 to n, each cycle of two operations, the first operation adds the value of a1 to aj so that aj can be divisible by j, and the second operation moves all the values ​​of aj to a1 on.
Such a round of operation consumes 2n-2 times, all the values ​​of the entire sequence are moved to a1, and then for the subscripts from 2 to n again, and the value can be directly moved from a1 to the construction. A total of 3n-3 operations are consumed, and the structure must be completed.

#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=1e4+7;

ll num[maxn];
ll n,sum;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        sum=0;
        cin>>n;
        for(ll i=1;i<=n;i++) {
    
    cin>>num[i];sum+=num[i];}
        if(sum%n) cout<<-1<<endl;
        else
        {
    
    
            sum/=n;
            cout<<3*(n-1)<<endl;
            for(ll i=2;i<=n;i++)//第一遍for把除了num[1]外的所有值清零,移动到num[1]上
            {
    
    
                ll temp=i-num[i]%i;
                if(temp==i) temp=0;
                cout<<1<<' '<<i<<' '<<temp<<endl;
                num[1]-=temp;
                num[i]+=temp;
                cout<<i<<' '<<1<<' '<<num[i]/i<<endl;
                num[1]+=num[i];
            }
            for(ll i=2;i<=n;i++) cout<<1<<' '<<i<<' '<<sum<<endl;//第二遍for直接利用num[1]构造
        }
    }
}

E title
operation, dfs divide and conquer, conclusion

题意为给定一个长度为n的只包含自然数的数列,你需要找到一个合适的值out,使得对原数列中每个数值都异或x后得到一个新数列,这个新数列中逆序对的数量num最小,输出这个最小的num和对应的out值。

这里需要认识到,假设只有0和1的数列,我们可以通过一次for循环的过程中,记录0和1出现了几次,以0和以1为结尾构成逆序对的数量,根据两个值的大小差别决定我们是用0还是用1去异或他们。
由此之后,
我们从高位到低位看,根据取值的不同,数列会被分为2的对应深度次方的几个集合,对于不同的集合来说,他们之间的逆序对数量是已经在前面的层数过程中根据上面一段的计算过程可以求得,之后各个集合之间再也不会产生影响,因为后续只对更低位产生影响,不会对当前集合之间的关系产生影响。
推到此处之后直接写一个dfs分治即可。

#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;
ll ans=0,out=0;//ans为最终的数列中逆序对的数量,out为对原数列中每个值进行异或的值

void dfs(vector<vector<ll>>now,int deep)//二维数组now记录数列在当前层数被分割成了几个部分,deep为当前算的是二进制第几位
{
    
    
    ll temp=1ll<<deep;
    ll cas0,cas1,sum0=0,sum1=0;//sum0和sum1分别记录当前二进制deep位上,以该位为0的值作为逆序对的右侧(也就是out在此位取0)的逆序对数量
    //和以该位为1的值作为逆序对的右侧(也就是out在此位取1,使得该位的所有数0和1转化)的逆序对数量
    vector<vector<ll>>next;//下一次dfs的二维数组
    vector<ll>next0,next1;//当前分割部分的vector中,二进制deep位为0和1的数字分别放入两个vector
    for(int i=0;i<now.size();i++)
    {
    
    
        cas0=cas1=0;
        for(int j=0;j<now[i].size();j++)
        {
    
    
            if(now[i][j]&temp) {
    
    sum1+=cas0;cas1++;next1.push_back(now[i][j]);}
            else {
    
    sum0+=cas1;cas0++;next0.push_back(now[i][j]);}
        }
        if(next0.size()) {
    
    next.push_back(next0);next0.clear();}//避免不需要的递归和空间浪费,如果next0和next1不为0才压入下次dfs的数组里
        if(next1.size()) {
    
    next.push_back(next1);next1.clear();}
    }
    if(sum0>sum1) {
    
    ans+=sum1;out+=temp;}//如果以该位为0的值作为逆序对右侧的逆序对数量大于以该位为1的值作为逆序对的右侧,代表out需要在该位取1
    else ans+=sum0;
    if(deep==0) return;
    dfs(next,deep-1);
}

int32_t main()
{
    
    
    IOS;
    cin>>n;
    vector<vector<ll>>num(1);
    num[0].resize(n);
    for(auto &x:num[0]) cin>>x;
    dfs(num,30);//dfs30层即可,1e9的最高位也不过2的30次
    cout<<ans<<' '<<out<<endl;
}

Guess you like

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