Codeforces Round #674 (Div. 3)A-F题解

Codeforces Round #674 (Div. 3)A-F题解

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

Question A
Water question does not write the solution

#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,x;
        cin>>n>>x;
        if(n<3) cout<<1<<endl;
        else cout<<(n-2)/x+((n-2)%x?1:0)+1<<endl;
    }
}

Question B
Simple structure

The title means given n 2 × \times× 2 matrices, you can use these matrices any number of times and ask to spell out an m× \times× m symmetrical matrix according to the main diagonal. Ask if it can be constructed.

According to whether the matrix is ​​on the main diagonal, we can notice the 2 × \times on the diagonal× 2 matrix also needs to be symmetrical according to its main diagonal, instead of the matrix on the main diagonal, the two need to be symmetrical to each other. It is not difficult to find that if there is a 2×matrix that satisfies the main diagonal\times× 2 matrices, then we can fill the non-diagonal part of these matrices directly to meet the requirements.

Therefore, the 2 × \times× 2 The existence of the matrix itself is just a matrix symmetric about the main diagonal, and m needs to be an even number.

#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 num[107][2][2];

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n,m;
        cin>>n>>m;
        bool flag=0;
        for(int i=0;i<n;i++)
        {
    
    
            for(int j=0;j<2;j++)
                for(int k=0;k<2;k++)
                    cin>>num[i][j][k];
            if(num[i][0][1]==num[i][1][0]) flag=1;
        }
        if(m%2==0&&flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

Question C
Simple structure, violence or simple conclusion

The question means that there is only one number 1 in the sequence at the beginning. You can add 1 to a number in the sequence or copy a certain number to the end of the sequence for each operation. Ask how many operations you need at least to make all the numbers in the sequence. The sum of the values ​​is not less than n.

We noticed that for each operation,
if the value +1 is selected, it will only have an effect of +1 on the whole, but the value after +1 will increase the maximum value that the copy operation can increase.
Copying a certain value will increase the value of the current maximum number, but will not affect the maximum value that can be increased by subsequent operations.

We directly choose to keep +1 to the first number, and keep copying this value after +1 reaches the appropriate size.
Suppose we first +1 to the value i, then the total number of operations is divided into two parts, the first part is the number of times +1 is i-1, and the second part is the number of times the value i is copied, which is n/i -1+n%i?1:0.
After pushing here, the direct violence for sqrt(n) can already be overcome.
But you can simply go deeper. If we increase i by 1, it will have an effect of +1 on the number of operations i-1 in the first part. Then in the second part, n/i-1+n%i?1:0 At least one must be subtracted from the part, and our +1 operation on i is positive. I have written the example of the sum of remainders in "Suan Jing" that may be more sensitive, or you can find this rule by writing it on your own manuscript. At this time, the value of i is sqrt(n) is the optimal. When i>=sqrt(n), when i changes, the step change of n/i cannot be greater than 1, which in turn corresponds to the case of i<sqrt(n).

#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;
        cin>>n;
        ll temp=sqrt(n);
        cout<<temp-1+n/temp-1+(n%temp?1:0)<<endl;
    }
}

Question D
Greedy, structure

The question means that given a sequence of numbers that does not contain 0, now you need to insert at least a few numbers into this sequence of numbers so that the sum of the values ​​of this sequence does not exist in a continuous interval is 0.

Here is the direct greedy strategy. Sweep from left to right. For the interval where the sum is 0 in the first paragraph, we must insert a number in the middle, and we can directly greedily insert it to the left of the rightmost element. An "infinity" value, in this case, the left part of the infinity value will not add up to 0 with the right part.

Here, if the interval is 0, you can use the map to record the occurrence of the prefix sum. Every time a certain interval appears and the sum is 0, the number of insertions is +1 and the map is cleared, and the value of the current position is recorded in the map.

#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;
    ll n,sum=0,ans=0;
    cin>>n;
    map<ll,bool>M;//M[x]记录前缀合x是否在前面出现过,如果当前前缀和为x,那么在当前位置到之前记录x的位置之间的数加起来为0
    M[0]=1;//0要初始化为出现过,意思为开头到目前为止所有部分的值加起来为0
    for(int i=0;i<n;i++)
    {
    
    
        ll x;
        cin>>x;
        sum+=x;
        if(M.find(sum)!=M.end())//如果当前前缀和和之前某个位置的相同,代表这两个位置间(包括当前位置)的值加起来为0
        {
    
    //贪心过程在当前位置前的一个位置塞入一个绝对值足够大的数字即可
            M.clear();
            sum=x;//当前前缀合变为刚读入的这个数,前面的数字不再对后续产生影响,可以理解为我们在前面一个位置插入了一个无穷大
            M[x]=M[0]=1;
            ans++;
        }
        else M[sum]=1;
    }
    cout<<ans<<endl;
}

Question E
Greed, small conclusions, violence

Two people play n rounds of rock-paper-scissors. Each person prepares to produce several times of scissors, several times of rock, and several times of paper. The minimum and maximum number of wins that the first person can obtain is required.

The maximum number of wins that can be obtained is easy to be greedy. Directly take the smaller value of the first person's scissors and the second person's cloth and add it to the answer. The other two situations are also the same.

The least number of wins that can be obtained requires a small conclusion. We can think in reverse. If we want to get the least number of wins, it is equivalent to get the most number of draws and losses. In the case of a draw and a negative field, the scissors can make a draw with scissors, or they can make a negative field with rocks.
We give priority to a tie, and here I artificially prescribe a word called "occupied". For example, once the first person’s scissors we arrange to correspond to the second person’s rock, and once the first person’s rock should be the second person’s rock. The personal stone correspondence is now forced to correspond with the cloth after being "squeezed".
If Rock, Paper, Scissors are in a state of "occupied", it is not difficult to find that it constitutes a three-game negative cycle. We can completely make them a draw in all three games and eliminate these three "occupied" states. It can be concluded that the optimal situation can inevitably be transformed into a solution in rock-paper-scissors that does not exist in the "occupied" state, that is, giving priority to one of the three methods.
Therefore, we directly for 3 times, giving priority to the number of draws and negatives that can be obtained by the three methods, and the answer is the largest and subtracted.

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

ll a[3],b[3];

int32_t main()
{
    
    
    IOS;
    ll n;
    cin>>n;
    cin>>a[0]>>a[1]>>a[2];
    cin>>b[0]>>b[1]>>b[2];
    ll ans=0;//记录最高可以得到的负场和平局数量
    for(int i=0;i<3;i++)//优先考虑a中的哪一个
    {
    
    
        ll now=0,sum=0;//now记录位置有多少场次需要寻找平局和负场,sum为优先考虑a[i]的情况下得到的负场和平局数
        for(int j=0;j<3;j++)
        {
    
    
            int tar=(i-j+3)%3;//寻找当前位置的下标,现在是尽可能多的寻找平局和负场
            ll temp=b[tar];
            sum+=min(now,temp);temp-=min(now,temp);//上一个位置留下的部分可以在当前位置放
            now=a[tar];//放置后上一个位置的场次没被安排的无法保存到下一个,直接清零记录为当前位置的场次即可
            sum+=min(now,temp);now-=min(now,temp);//当前位置b仍然能安排的优先安排
        }
        ans=max(ans,sum);
    }
    cout<<n-ans<<' ';
    ans=0;
    for(int i=0;i<3;i++) ans+=min(a[i],b[(i+1)%3]);
    cout<<ans<<endl;
}

F title
dp

The question means that given a string, only contains abc? Four characters, of which? Characters can be replaced by any one of abc, ask all? In all the strings after replacement, the substring abc (subscripts are not necessarily consecutive) appeared several times in total.

We noticed that if we look from left to right, what we actually need to pay attention to is that a, ab, abc appear several times. Then we can make a 3 × \times according to the i-th position is a, b, c× n linear dp.
First of all, the situation of the current position must inherit all the construction schemes of the previous position (see the trans function). After that, three different conversions are performed according to whether the current position structure is a, b, or c.
If a is constructed, it will only affect the number of a. If x question marks appear before the current position, then there are 3xconstruction methods infront at this time, and each method will add an a. Therefore directly increase 3xa.
If b is constructed, it will only affect the number of a, so just increase the number of all a recorded in the previous position.
If c is constructed, it will only affect the number of abc, just increase the number of all abs recorded in the previous position.

#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 mod=1e9+7;
const ll maxn=2e5+7;

struct Node
{
    
    
    ll a,ab,abc;
};

Node dp[maxn][3];//dp[i][j]表示第i个字符构造j的情况下,a/ab/abc各自出现了几次,j=0代表构造字符'a',j=1代表构造'b',j=2代表构造'c'
//当s[i]是个确定的字符时,只转移到dp[i][0]上
int n;
ll cas=1;//记录3^k,用于构造'a'时的转移
char s[maxn];

void trans(int x,int y)
{
    
    
    for(int i=0;i<3;i++)
    {
    
    
        dp[x][y].a=(dp[x][y].a+dp[x-1][i].a)%mod;
        dp[x][y].ab=(dp[x][y].ab+dp[x-1][i].ab)%mod;
        dp[x][y].abc=(dp[x][y].abc+dp[x-1][i].abc)%mod;
    }
}

void transa(int x,int y)//构造a时的转移方式
{
    
    
    trans(x,y);
    dp[x][y].a=(dp[x][y].a+cas)%mod;
}

void transb(int x,int y)//构造b时的转移方式
{
    
    
    trans(x,y);
    dp[x][y].ab=(dp[x][y].ab+dp[x-1][0].a+dp[x-1][1].a+dp[x-1][2].a)%mod;
}

void transc(int x,int y)//构造c时的转移方式
{
    
    
    trans(x,y);
    dp[x][y].abc=(dp[x][y].abc+dp[x-1][0].ab+dp[x-1][1].ab+dp[x-1][2].ab)%mod;
}

int32_t main()
{
    
    
    IOS;
    cin>>n>>(s+1);
    for(int i=1;i<=n;i++)
    {
    
    
        if(s[i]=='?')
        {
    
    
            transa(i,0);
            transb(i,1);
            transc(i,2);
            cas=cas*3%mod;
        }
        else
        {
    
    
            if(s[i]=='a') transa(i,0);
            if(s[i]=='b') transb(i,0);
            if(s[i]=='c') transc(i,0);
        }
    }
    cout<<(dp[n][0].abc+dp[n][1].abc+dp[n][2].abc)%mod<<endl;
}

Guess you like

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