CSP 2021-09-2 non zero segment division problem solution

Keywords: C++ Algorithm CSP

Title Link

The original question is linked in Non zero segment division , I won't post the title. Given an array, you can divide the array into as many continuous non-zero segments as possible by changing the number below the threshold into 0.

Topic analysis

A very direct idea is: there are m different non-zero values in the array with length n. We use these m values as the threshold respectively, and then calculate the number of consecutive non-zero segments in this case, and the final answer takes the maximum value. The next question is how to realize this idea.
First, for any monotonic array, no matter how we determine this threshold, we will not change the number of non-zero segments of the array.
Then let's consider two simple cases:
Given natural numbers a, B, C (a > b > C) (in practice, several numbers may be equal: when three numbers are congruent, they are treated as a monotonic array; in addition, all other cases can be treated with the following ideas), there may be the following two non monotonic cases:

[a,c,b]

In this case, if we make three numbers as the threshold in the order of c, b and a, the number of non-zero continuous segments remains unchanged when we take c as the threshold; When we take b as the threshold (that is, let c become 0), the number of non-zero consecutive segments of the original array + 1; They are:

[a],[a]

When we take a as the threshold, the number of non-zero continuous segments is - 1.

[b,a,c]

In this case, when we take b or c as the threshold, the number of non-zero continuous segments remains unchanged; When we take a as the threshold, the number of non-zero continuous segments of the original array is - 1.

Therefore, first we traverse the original array and record the number of non-zero consecutive segments, and then we can traverse the array in some order. When traversing a number a i ( 1 < i < n ) a_i(1<i<n) ai (1 < I < n) a i a_i Set the number of ai {to 0) and pair the subarray [ a i βˆ’ 1 , a i , a i + 1 ] [a_{i-1},a_i,a_{i+1}] [ai − 1, ai, ai+1] discuss by situation:

  1. When the subarray is monotonous, the number of non-zero continuous segments does not change;
  2. When the sub array belongs to the first case above, the number of segments + 1;
  3. In the second case, the number of segments is - 1.

However, we haven't considered the first element of the array a 1 a_1 a1 and the last element a n a_n an​. For the first element, when a 1 < a 2 a_1<a_2 The number of segments did not change when a1 < A2; Otherwise, the number of segments is - 1. For the last element, when a n < a n βˆ’ 1 a_n<a_{n-1} The number of segments did not change when an < an − 1; Otherwise, the number of segments is - 1.

For convenience, we can make the non-zero numbers in the original array as the threshold in the order from small to large (sorting algorithm), and then process them according to the above method.

Thought optimization

1. Optimization for traversal

The time complexity of sorting is O ( n log ⁑ n ) O(n\log n) O(nlogn), and in fact, we have more efficient O ( n ) O(n) O(n) algorithm to do this. What we really need to do is to store all the subscripts of each number in the array, and then traverse these subscripts according to the size of the number. In fact, the methods we can use include but are not limited to hash, pointer array, adjacency list and even chain forward star. I use chain forward star.

2. Optimization for original array

Sometimes in the original array, this happens (a,b,c are not equal to each other):

[a,b,b,c]
  1. When a > b > C or a < B < C, the subarray is a monotone array. Selecting the threshold in the array will not change the number of segments.
  2. When a > b and B < C, the situation is similar to the previous treatment idea and treated in the same way.
  3. When a < B, b > C, the situation is similar to that before, and the same method is used.

According to the above analysis, we know that the processing method and result of [a,b,b,c] are the same as those of [a,b,c]. Therefore, we can compress the original array when reading in: compress the consecutive equal segments into one number.
This will reduce the size of the array, so as to achieve the effect of optimization.

Source code (100 points)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=1e4+5,N=5e5+5;
int num[N],cnt=0,tn=0,n=0,maxnum=0,cntmax=0,head[MAX],to[N],nxt[N],edgcnt=0,t;
inline void addedge(int u,int v)
{
    nxt[++edgcnt]=head[u];
    head[u]=edgcnt;
    to[edgcnt]=v;
}
int main()
{
    scanf("%d",&tn);
    memset(num,0,sizeof num);
    memset(head,0,sizeof head);
    memset(to,0,sizeof to);
    memset(nxt,0,sizeof nxt);
    n=1;
    scanf("%d",num+1);
    for(int i=2;i<=tn;i++)//When reading in, compress the original array and record the maximum value of the array
    {
        scanf("%d",&t);
        if(t!=num[n]) num[++n]=t,maxnum=max(maxnum,num[n]);
    }
    for(int i=1;i<=n;i++)//Chain forward star construction map
    {
        int &t=num[i];
        if(t) addedge(t,i);
    }
    for(int i=1;i<=n;i++)//Record the number of non-zero continuous segments
        if(num[i])
        {
            while(num[++i]&&i<=n);
            cnt++;
        }
    cntmax=cnt;//In practice, the possible optimal solution is not to operate on the original array
    for(int i=1;i<maxnum;i++)//Traverse all nonzero numbers
    {
        for(int j=head[i];j;j=nxt[j])
        {
            int &t=to[j];
            if(t==1&&!num[2]) cnt--;
            else if(t==n&&!num[n-1]) cnt--;
            else if(num[t-1]&&num[t+1]) cnt++;
            else if(!num[t-1]&&!num[t+1]) cnt--;
            num[t]=0;//After traversing a number, set it to zero to simplify the judgment conditions
        }
        cntmax=max(cntmax,cnt);
    }
    printf("%d",cntmax);
    return 0;
}

Posted by AaZmaN on Fri, 01 Oct 2021 17:05:23 -0700