【Horseshoe Collection】Week 12 - Topic on Prefix Sum and Difference

Topics on prefix sums and differences






MT2056 Second-order prefix sum

Difficulty: Gold Time limit: 1 second Memory usage: 128M
topic description

In a Cartesian coordinate system, there are nnThere are element values ​​on n coordinates (the element values ​​of the remaining coordinates are 0), now given the coordinates of some points( xi , yi ) \left(x_i,y_i\right)(xi,yi) and the element value vi v_iof this coordinatevi, calculated with a side length RRThe positive rectangle of R can contain the maximum value of the sum of coordinate element values. The border of the square is not included.

Format

Input format: the first line of the input file is two positive integers nnn andRRr ;;
     nextnnThere are 3 natural numbers in each line of n lines, representing xi , yi , vi x_i, y_i, v_ixi,yi,vi.
Output format: The output file only has one positive integer, indicating that a square can contain at most the sum of the largest element values ​​on the map.

sample 1

Input: 2 1

   0 0 1
   1 1 1

Output: 1

Remark

It is not guaranteed that the given data coordinates are not repeated. If there are inputs with the same coordinates, please set their vi v_iviAccumulate and treat it as a coordinate;
1 ≤ n , R ≤ 1000 , 0 ≤ xi , yi ≤ 1000 , 0 ≤ vi ≤ 10 8 1\le n,R\le1000,\ 0\le x_i,y_i\le1000,\ 0\le v_i\le{10}^81n,R1000, 0xi,yi1000, 0vi108

The sides of the square must be aligned with x , yx,yx,The y- axis is parallel.


Relevant knowledge points: 前缀和与差分


answer


As the name suggests, the question is about the two-dimensional prefix sum (if you don’t know this data structure, please go to: prefix sum and difference ). The mathematical formula for constructing the two-dimensional prefix sum is directly given below:

p r e f i x [ i ] [ j ] = ∑ x = 1 i ∑ y = 1 j m a t r i x [ x ] [ y ] prefix\left[i\right][j]=\sum_{x=1}^i\sum_{y=1}^jmatrix[x][y] prefix[i][j]=x=1iy=1jma t r i x [ x ] [ y ]

It means from position matrix[ 1 ][ 1 ] matrix[1][1]matrix[1][1] m a t r i x [ i ] [ j ] matrix[i][j] ma t r i x [ i ] [ j ] The sum of all elements between these. Ordinal pair ( x 1 , y 1 ) , ( x 2 , y 2 ) \left(x_1,y_1\right),\ \left(x_2,y_2\right) at given two indicated
positions(x1,y1), (x2,y2) , the formula for solving the element sum of the specified subarray through the two-dimensional prefix sum array is:
S = prefix [ x 2 ] [ y 2 ] − prefix [ x 1 − 1 ] [ y 2 ] − prefix [ x 2 ] [ y 1 − 1 ] + prefix [ x 1 − 1 ] [ y 1 − 1 ] S=prefix[x_2][y_2]-prefix[x_1-1][y_2]-prefix[x_2][y_1-1]+prefix[ x_1-1][y_1-1]S=prefix[x2][y2]prefix[x11][y2]prefix[x2][y11]+prefix[x11][y11]

The following directly gives the complete code based on the above formula (already AC):

/*
    MT2056 二阶前缀和 
    
*/

#include<bits/stdc++.h> 
using namespace std;

const int MAX = 1005;
int ary[MAX][MAX], prefix[MAX][MAX], ans;

int main( )
{
    
    
    // 录入数组内容的同时构建二维前缀和
    int n,R,x,y,v; cin>>n>>R;
    while(n--){
    
    
        cin>>x>>y>>v;
        ary[++x][++y] += v;
    }

    // 计算二维前缀和
    for(int i=1;i<1001;i++)
        for(int j=1;j<=1001;j++)
            prefix[i][j] += prefix[i-1][j]+prefix[i][j-1]-prefix[i-1][j-1]+ary[i][j];
            
     // 寻找指定范围的最大子阵
     for(int i=R;i<1001;i++)
        for(int j=R;j<=1001;j++)
            ans = max(ans, prefix[i][j]-prefix[i-R][j]-prefix[i][j-R]+prefix[i-R][j-R]); 
    
    // 输出结果 
    cout<<ans<<endl;
    
    return 0;
}


MT2057 Tickets

Difficulty: Diamond Time limit: 1 second Memory usage: 128M
topic description

A theme park near Brother Xiaoma's home recently held an event, and Brother Xiaoma won the first prize in the event. And the first prize is a long string of paper slips with nn on itThere are n grids, each grid has a number, the event staff told Xiaoma, as long as he cuts a continuous grid, the sum of the numbers in the grid divided by the number of cut grids is greater than or equal to the ticket feettt,那么小码哥就能用这段格子抵消门票费。
小码哥想要尽可能多的利用这个奖品,为此他想先知道有多少种裁剪的方案能裁出一段能抵消门票费的格子。
由于方案数可能很大所以需要你输出方案数对1e9+7取模的结果。

格式

输入格式:第一行两个正整数整数 n n n t t t ,分别表示格子的数量和门票费;
     第二行 n n n 个整数 a i a_i ai ,表示格子内的数字。
输出格式:输出一个整数,表示总方案数对1e9+7取模的结果。

样例1

输入: 5 4
   3 4 2 3 5

输出:3

备注

其中: 1 ≤ n ≤ 10 6 , 1 ≤ t ≤ 10 8 ,   0 ≤ a i ≤ 2 × 10 8 1\le n\le{10}^6,1\le t\le{10}^8,\ 0\le a_i\le{2\times10}^8 1n106,1t108, 0ai2×108


相关知识点:前缀和与差分归并排序


题解


实际上,题目的要求是找出指定序列中所有“均值不低于指 t t t 的子序列”个数。一个很直观的想法是,既然你要求序列均值不低于 t t t , then we can combine each number in the original sequence withttt difference, in this way, once the sum of a certain sequence in the obtained new sequence is greater than 0, it means that the average value of this sequence is greater thanttt 's (i.e. the sequence that meets the requirements):

insert image description here

However, to enumerate the subsequences in a sequence, its time complexity is O ( n 2 ) O\left(n^2\right)O(n2 )if also summing each subsequenceO ( n ) O\left(n\right)O( n ) , the time complexity climbs toO ( n 3 ) O\left(n^3\right)O(n3 ), which must be timed out for this question. Speaking of "interval sum", perhaps you will quickly think of the structure of "prefix sum". After adding the prefix sum, the interval summation is fromO ( n ) O\left(n\right)O( n ) down to a constant level, which will greatly speed up the search. Therefore, during data input, we can directly construct the original array andttPrefix sum of difference of t :

for(int i=1;i<=n;i++){
    
    
   cin>>num;
   prefix[i] = prefix[i-1] + num - t;
}

But adding the prefix sum only speeds up the process of summing the intervals, and finding the subsequence is still O ( n 2 ) O\left(n^2\right)O(n2 ), still timeout. So the key to the problem now is: how to quickly find the mean value greater thanttsubsequence of t ? Or how to find the increasing subsequence from the prefix and the array. Why increment? Because for prefixes and arrays, as long asi < j i<ji<j ,存在 p r e f i x [ i ] ≤ p r e f i x [ j ] prefix\left[i\right]\le prefix\left[j\right] prefix[i]prefix[ j ] , it means the interval[ i + 1 , j ] [i+1,j][i+1,The sum of all the numbers in j ] is not less than 0. According to the above analysis, it can be known (the prefix[] array is "the original array andttThe prefix of the difference between t and "), then suchprefix[] prefix[]prefix[] 在出现 p r e f i x [ i ] ≤ p r e f i x [ j ]   ( i < j ) prefix\left[i\right]\le prefix\left[j\right]\ (i<j) prefix[i]prefix[j] (i<j ) , it means that its mean value is greater thanttt . For example, for the sequence given in the title (assuming that the array indexes all start from 1):
{ 3 , 4 , 2 , 3 , 5 } \{3, 4, 2, 3, 5\}{ 3,4,2,3,5}

Its corresponding "and t = 4 t=4t=The prefix sum of the difference of 4
" array is : { − 1 , − 1 , − 3 , − 4 , − 3 } \{-1, -1, -3, -4, -3\}{ 1,1,3,4,3}

In this array, the increment interval is [ 4 , 5 ] [4,5][4,5 ] , corresponding toprefix [ 4 ] = − 4 , prefix [ 5 ] = − 3 prefix[4]=-4,prefix[5]=-3prefix[4]=4,prefix[5]=3 ,而 p r e f i x [ 5 ] ≥ p r e f i x [ 4 ] prefix\left[5\right]\geq prefix\left[4\right] prefix[5]prefix[ 4 ] , so it is considered that a mean value not lower than t = 4 t=4has been foundt=4 subintervals, compared tottt 增加了 p r e f i x [ j ] − p r e f i x [ i ] = p r e f i x [ 5 ] − p r e f i x [ 4 ] = p r e f i x [ 5 ] − p r e f i x [ 4 ] = 1 prefix[j]-prefix[i]=prefix[5]-prefix[4]=prefix[5]-prefix[4]=1 prefix[j]prefix[i]=prefix[5]prefix[4]=prefix[5]prefix[4]=1 . Let's verify it from the original array:

原数组中, a r y [ 4 + 1 ] = a r y [ 5 ] = 5 , a r y [ 5 ] = 5 ary[4+1]=ary[5]=5,ary[5]=5 ary[4+1]=ary[5]=5,ary[5]=5 ,因此该子段的均值为 ( 5 + 5 ) / 2 = 5 (5+5)/2=5 (5+5)/2=5,这与我们通过前缀和得到的结论一致(均值增加了1)。

到这一步,我们实际上将原问题转换为:“求原数组与 t t t 之差的前缀和数组中,所有 i < j i<j i<j p r e f i x [ i ] ≤ p r e f i x [ j ] prefix\left[i\right]\le prefix\left[j\right] prefix[i]prefix[ j ] number to number". Taking the sequence given in the title as an example, it can be found that it is the same asttIn the prefix sum array of the difference between t , the number pairs that meet the requirements are:

i = 1 ,   j = 2 i=1,\ j=2 i=1, j=2 时, p r e f i x [ 1 ] = − 1 ≤ − 1 = p r e f i x [ 2 ] prefix\left[1\right]=-1\le-1=prefix\left[2\right] prefix[1]=11=prefix[ 2 ] , corresponding to the original sequence interval[ i + 1 , j ] = [ 2 , 2 ] [i+1, j] = [2, 2][i+1,j]=[2,2 ] , the mean is4 / 1 = 4 4/1=44/1=4
i = 3 ,   j = 5 i=3,\ j=5 i=3, j=5 时, p r e f i x [ 3 ] = − 3 ≤ − 3 = p r e f i x [ 5 ] prefix\left[3\right]=-3\le-3=prefix\left[5\right] prefix[3]=33=prefix[ 5 ] , corresponding to the original sequence interval[ i + 1 , j ] = [ 4 , 5 ] [i+1, j] = [4, 5][i+1,j]=[4,5 ] , the mean is( 3 + 5 ) / 2 = 4 (3+5)/2=4(3+5)/2=4
i = 4 ,   j = 5 i=4,\ j=5 i=4, j=5 时, p r e f i x [ 4 ] = − 4 ≤ − 3 = p r e f i x [ 5 ] prefix\left[4\right]=-4\le-3=prefix\left[5\right] prefix[4]=43=prefix[ 5 ] , corresponding to the original sequence interval[ i + 1 , j ] = [ 5 , 5 ] [i+1, j] = [5, 5][i+1,j]=[5,5 ] , the mean is5 / 1 = 5 5/1=55/1=5

while "all i < j i<ji<j p r e f i x [ i ] ≤ p r e f i x [ j ] prefix\left[i\right]\le prefix\left[j\right] prefix[i]prefix[ j ] number of pairs" actually expresses the meaning of "non-reversed pair".

Q: What is a "non-reversed pair"?
Answer: As long as it is not a "reversed pair", it is a "non-reversed pair".
Q: So what is a "reversed pair"?
Answer: In an array ary [ ] = { a 1 , a 2 , … , an } ary[\ ]=\{a_1,a_2,…,a_n\}oh my [ ] ={ a1,a2,,an} , ifi < j i<ji<j i , j i,j i,j is a non-negative integer), andary [ i ] > ary [ j ] ary[i]>ary[j]a ry [ i ]>a ry [ j ],则称( and [ i ] , and [ j ] ) (and[i],and[j])( and ry [ i ] ,a ry [ j ]) is the arrayary [ ] ary[\ ] A reversed pair in a ry [ ] .

Therefore, the original question can be transformed into: "Find the original array and ttThe prefix of the difference between t
and the number of non-reversed pairs in the array". The most primitive way to solve the non-reversed pair is to use double loops to enumerate, and its time complexity isO ( n 2 ) O\left(n^2 \right)O(n2 ). Of course, there is an optimization algorithm: use merge sort to solve the number of reversed pairs, the time complexity of this algorithm isO ( nlogn ) O\left(nlogn\right)O(nlogn)

Merge sort is one of the nine sorting algorithms, and it is a stable sorting algorithm. Its implementation mainly includes top-down and bottom-up (refer to blog: https://blog.csdn.net/u012294613/article/ details/125527224 ), from the perspective of code implementation, the top-down algorithm based on recursive thinking is more commonly used. The main ideas are as follows:

  • Partition problem: Divide the sequence into two sequences with the same number of elements as possible;
  • Recursive solution: continue to perform merge sort on subsequences;
  • Merge problem: Merge the two ordered sequences obtained in 2.

As can be seen from the above, sorting will not be performed when the sequence is passed into the function at the beginning, because the processing object of the "sorting" operation is an "ordered sequence", and when the sequence to be sorted is passed in for the first time, its total is treated as an "unordered sequence", so the first operation performed on the passed sequence is always division. And when the length of a certain "sequence" is 1, the sequence must be in order. At this time, the algorithm actually starts to sort (that is, step 3, which is actually sorting the sequence in the process of merging). ). Here is an example to illustrate the process of merge sorting:
{ 24 , 5 , 4 , 37 , 12 , 16 , 7 , 9 , 6 } \left\{24,\ 5,\ 4,\ 37,\ 12,\ 16 ,\ 7,\ 9,\ 6\right\}{ 24, 5, 4, 37, 12, 16, 7, 9, 6 }
When this sequence is passed to the recursive function of merge sort, it will be divided first, and two subsequences will be obtained:{ 24 , 5 , 4 , 37 } , { 12 , 16 , 7 , 9 , 6 } \left \{24,\ 5,\ 4,\ 37\},\{12,\ 16,\ 7,\ 9,\ 6\right\}{ 24, 5, 4, 37},{ 12, 16, 7, 9, 6 } , then these two subsequences will also be passed into the recursive function, and the recursive decomposition will be performed continuously, and so on, until the sequence is finally divided into several subsequences with a length of 1, namely: { 24 } ,{ 5 } , { 4 } , { 37 } , { 12 } , { 16 } , { 7 } , { 9 } , { 6 } \left\{24\right\},\ \left\{5\right\} ,\{4\},\{37\},\{12\},\{16\},\{7\},\{9\},\{6\}{ 24}, { 5},{ 4},{ 37},{ 12},{ 16},{ 7},{ 9},{6} . _ _ At this point, for each subsequence (which has reached the end of its respective recursive function, that is, it will not be divided again), it means that its length is 1, which means that each sequence is now in order, so the steps are started 3 (Note: When merging, the selected two subsequences are adjacent).

  • First merge: { 5 , 24 } , { 4 , 37 } , { 12 , 16 } , { 7 , 9 } , { 6 } \left\{5,\ 24\right\},\{4,\ 37\},\{12,\ 16\},\{7,\ 9\},\{6\}{ 5, 24},{ 4, 37},{ 12, 16},{ 7, 9},{ 6}
  • Second merge: { 4 , 5 , 24 , 37 } , { 7 , 9 , 12 , 16 } , { 6 } \left\{4,\ 5,\ 24,\ 37\right\},\{7 ,\ 9,\ 12,\ 16\},\{6\}{ 4, 5, 24, 37},{ 7, 9, 12, 16},{ 6}
  • The third merge: { 4 , 5 , 7 , 9 , 12 , 16 , 24 , 37 } , { 6 } \left\{4,\ 5,\ 7,\ 9,\ 12,\ 16,\ 24, \ 37\right\},\{6\}{ 4, 5, 7, 9, 12, 16, 24, 37},{ 6}
  • The fourth merge: { 4 , 5 , 6 , 7 , 9 , 12 , 16 , 24 , 37 } \left\{4,\ 5,\ 6,\ 7,\ 9,\ 12,\ 16,\ 24 ,\ 37\right\}{ 4, 5, 6, 7, 9, 12, 16, 24, 37}

The algorithm ends and the sorting is completed.

The core of merge sorting is the third step to perform the merge process. The implementation method is very simple. Since the two sequences processed each time are in order, he takes out the current most value from the two sequences each time. After the comparison, the most value in the comparison result is inserted into the temporary array, and so on, until the two sequences are empty, the sorting of the two subsequences is completed (the final ordered array is temporarily stored in the temporary array ).

下面给出归并排序的完整代码:

/**
* 对 ary 数组中 [l,r] 区间内的元素进行排序
*
* @param l 区间左边界,闭区间
* @param r 区间右边界,闭区间
*/
void merge_sort(int ary[], int l , int r)
{
    
    
    // 递归终止条件 
    if(l >= r) return;
    
    // 划分区间的中间位置
    int mid = (l+r) >> 1;
    
    // 对两个子序列分别排序
    merge_sort(ary,l,mid);
    merge_sort(ary,mid+1,r);
    
    // 定义两个子序列的指针以及合并数组的指针
    int i = l, j = mid+1, pos=0; 
    
	// 归并子序列
	while(i<=mid && j<=r){
    
    
        if(ary[i] <= ary[j]) mergeAry[pos++] = ary[i++];
        else mergeAry[pos++] = ary[j++];
    }
    while(i<=mid) mergeAry[pos++] = ary[i++];
    while(j<=r) mergeAry[pos++] = ary[j++];
    
    // 将归并数组中排好序的元素复制到原始数组中(以供迭代),使原始数组中[l,r]区间内的元素有序 
    for(i=l, j=0; i<=r;i++,j++) ary[i] = mergeAry[j];
}

从归并排序的算法流程中注意到一件事:每次在对子序列执行归并时,都涉及到若干次的数字比较(比较两个子序列中各数的大小关系)。而各个子序列最终都会被归并至一个数组中,那这就是说,全部的数字都会参与到相对大小的比较中,这正好可用于统计逆序数!需要注意的是,如果采用归并排序统计逆序数,应当要构建升序序列;反之,如果要统计非逆序数,则应当构建降序序列。

于是,根据上述代码可写出求解本题的完整代码(已 AC):

/*
    MT2057 门票 
*/

#include<bits/stdc++.h> 
using namespace std;

const int MAX = 1e6+5;
const int MOD = 1e9+7; 
long ans=0, prefix[MAX], tmp[MAX]; 

void merge_sort(int l, int r, long ary[])
{
    
    
    // 递归终止条件 
    if(l>=r) return;
    // 序列划分中点 
    int mid = (l+r) >> 1;
    // 对子序列分别排序 
    merge_sort(l, mid, ary);
    merge_sort(mid+1, r, ary);
    // 定义两个子序列的指针以及合并数组的指针
    int i=l, j=mid+1, t=0;
    // 归并子序列
    while(i<=mid && j<=r){
    
    
        // 构建降序序列,直接统计非逆序数 
        if(ary[i] <= ary[j]){
    
    
            tmp[t++] = ary[j++];
            ans += mid-i+1;
            ans %= MOD;
        }
        else tmp[t++] = ary[i++];
    }
    while(i<=mid) tmp[t++] = ary[i++];
    while(j<=r) tmp[t++] = ary[j++];
    // 将归并数组中排好序的元素复制到原始数组中(以供迭代),使原始数组中[l,r]区间内的元素有序
    for(int i=l, j=0; i<=r;i++,j++) ary[i] = tmp[j];
}

int main( )
{
    
    
    // 录入数据 
    int n,t,num; cin>>n>>t; 
    for(int i=1;i<=n;i++){
    
    
        cin>>num;
        // 构建原数组与 t 之差的前缀和数组
        prefix[i] = prefix[i-1] + num - t;
    }
    // 利用归并排序计算非逆序数 
    merge_sort(0,n,prefix);
    // 输出结果 
    cout<<ans%MOD<<endl;
    
    return 0;
}


MT2058 最大的平均值

难度:黄金    时间限制:1秒    占用内存:128M
题目描述

给一个长度为 n n n 的数组,找一个长度大于等于 m m m 的子区间,使这个区间的元素的平均值最大。

格式

输入格式:第一行输入整数 n n n m m m ,数据用空格隔开;
     接下来输入 n n n 个整数。
输出格式:输出一个整数,表示平均值的最大值乘以1000再向下取整之后得到的结果。

样例 1

输入:10 6
   6 4 2 10 3 8 5 9 4 1
输出:6500

备注

其中: 1 ≤ n ≤ 100000 ,   1 ≤ m ≤ n ,   0 ≤ a i ≤ 10 7 1\le n\le100000,\ 1\le m\le n,\ 0\le a_i\le{10}^7 1n100000, 1mn, 0ai107


Relevant knowledge points:前缀和与差分分治


answer


This question is exactly the same as the average number of [Luogu] P1404 . I wrote the solution for this question separately: ☞Portal

The complete code for solving this problem is directly given below (already AC):

/*
    MT2058 最大的平均值 
    洛谷 P1404
*/

#include<bits/stdc++.h> 
using namespace std;

const int MAX = 1e5+5;
int ary[MAX];
double prefix[MAX],eps=1e-8;

// 此函数用于判断:原数组中是否存在长度不低于 m 的子序列,使得其均值大于 thresold 
bool anySeq(int ary[], int n, int m, double thresold){
    
    
    double minGap = 0;
    
    // 计算以 thresold 为基准值得到的差值数组的前缀和数组
    for(int i=1;i<=n;i++){
    
    
        prefix[i] = prefix[i-1] + (ary[i]-thresold);
        
        // 当 i 不低于 m 时,就能检测子序列的存在情况了
        if(i>=m) {
    
    
            minGap = min(minGap, prefix[i-m]);
            
            // 只要该前缀和数组中存在不低于 0 的值,说明一定存在某个序列能使其均值大于 thresold 
            if(prefix[i]>minGap) return true;
        }
    } 
    
    return false; 
}

int main( )
{
    
    
    // 录入数据 
    int n,m,maxtmp=-1; cin>>n>>m; 
    
    // 录入原始数组,并记录最大值(该最大值表明此数组能取到的最大平均值即为该值) 
    for(int i=1;i<=n;i++){
    
    
        cin>>ary[i];
        maxtmp = max(maxtmp, ary[i]);
    }
    
    // 对最大平均值进行二分查找
    double minave = 0, maxave = maxtmp, midave;
    
    // 这里必须用精度进行控制,否则会超时 
    while(maxave - minave >= eps){
    
    
        
        // 设置当前的均值 
        midave = (minave+maxave) / 2;
        
        // 判断当前数组是否存在能大于该平均值的序列(长度不低于 m) 
        if(anySeq(ary, n, m, midave)) minave = midave;
        else maxave = midave;
    } 
    
    // 进行放大后再输出 
    cout<<int(maxave*1000)<<endl;
    
    return 0;
}


MT2068 Advanced Mathematics Exam

Difficulty: Gold Time limit: 1 second Memory usage: 128M
topic description

The high school math exam is over, and it's time for the math teacher to deal with it again. The math teacher wants to make a profit for her classmates. She always has to add points (both positive integers) to some classmates over and over again, and pay attention to the minimum score. Can you help her because of the heavy workload?

Format

Input format: the first line has two integers n, pn,\ pn, p respectively represent the number of students and the number of times to increase the score;
     the second line hasnnn integersa 1 − an a_1-a_na1an, represents the initial grade of each student;
     next ppP lines, each line has three numbersx , y , zx,y,zx,y,z means to thexxx toyyy students each increasezzZ points.
Output format: output only one line, representing the lowest score of the whole class after changing the score.

sample 1

Input: 3 2
   1 1 1
   1 2 1
   2 3 1

Output: 2

Remark

For 40% of the data, there is $n\le{10}^3;
for 60% of the data, there is $n\le{10}^4;
for 80% of the data, there is $n\le{10}^5 ;
For 100% data, there is $n\le{5\times10}^6;
p ≤ n , the students' preliminary test scores ≤ 100 , z ≤ 100 p\le n, the students' preliminary test scores\le100,\ z\le100pn , the student's initial test score100, z100


Relevant knowledge points: 前缀和与差分


answer


The requirement of this question is that the system gives several sets of operation requests (three parameters x , y , zx, y, zx,y,z ), each request requires you to put the interval[ x , y ] \left[x,y\right][x,y ] pluszzz , its essence is more like a "simulation" type of question. But look at the data range,nnThe maximum value of n can be5 × 1 0 6 5 × 10^65×106,且p ≤ np\le npn . So, if it is true every time for the interval[ x , y ] \left[x,y\right][x,y ] will definitely time out for the addition operation. Therefore, this requires the use of some special data structures.

For the case of uniform increase and decrease operations on continuous arrays, there is a special data structure: difference (students who are not yet clear about this data structure can move to: prefix sum and difference ).

The following is a brief explanation of it. First, the difference array is defined as follows:
subfix [ i ] = ary [ i ] − ary [ i − 1 ] subfix[i]=ary[i]-ary[i-1]subfix[i]=a ry [ i ]a ry [ i1 ]
Among them,subfix [ ] subfix[\ ]s u b f i x [ ]  is the difference array,ary [ ] ary[\ ]a ry [ ]  is the original array of input.

It is not difficult to see from the definition of the difference array that it records the difference in the continuous array. If we perform a unified increase or decrease operation on a certain continuous sub-section in the array, their relative size will not change for this series of data; looking at the entire array, it will only affect the beginning and end of the sub-section The relative magnitude of two numbers at their boundaries. For example, for the following array (assuming the index of the array starts counting from 1):
ary [ ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ary[\ ]=\{1,2,3, 4,5,6,7,8\}oh my [ ] ={ 1,2,3,4,5,6,7,8}

The corresponding difference array can be obtained as:
subfix [ ] = { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 } subfix[\ ]=\{1,1,1,1,1,1,1 ,1\}subfix[ ]={ 1,1,1,1,1,1,1,1}

If we add 4 to the number of the original array in the interval \left[3,\ 6\right]\, we get:
ary [ ] = { 1 , 2 , 7 , 8 , 9 , 10 , 7 , 8 } ary[ \ ]=\{1,2,7,8,9,10,7,8\}oh my [ ] ={ 1,2,7,8,9,10,7,8 }
The corresponding difference array is:
subfix [ ] = { 1 , 1 , 5 , 1 , 1 , 1 , − 3 , 1 } subfix[\ ]=\{1,1,5,1,1,1, -3,1\}subfix[] ={ 1,1,5,1,1,1,3,1 }
Observation arrayary [ ] ary[\ ]a ry [ ]  before and after interval increment operation, althoughary [ ] ary[\ ]a ry [ ]  has undergone considerable changes (that is, all the numbers in the specified interval), but in its corresponding difference array, only two places have changed: one is to specify the starting position of the value-added operation interval, and the other is to specify The next position at the end of the increment operation interval. It can be seen from this that when the difference array is used to record the original array, when the length of the original array ismmWhen the unified increase and decrease operation of m , it can change the time complexity fromO ( m ) O\left(m\right)O( m ) down to the constant level.

At the same time, based on the differential array formula, we can transpose it to get:
ary [ i ] = subfix [ i ] + ary [ i − 1 ] ary[i]=subfix[i]+ary[i-1]a ry [ i ]=subfix[i]+a ry [ i1]

And because the differential array is constructed, there are: ary [ 1 ] = subfix [ 1 ] ary[1]=subfix[1]a ry [ 1 ]=s u b f i x [ 1 ] , so the formula for restoring the original array from the differential array is as follows:
ary [ i ] = ∑ j = 1 isubfix [ j ] ary[i]=\sum_{j=1}^isubfix [j]a ry [ i ]=j=1isubfix[j]

Therefore, the complete code for solving this problem can be written as follows (AC):

/*
    MT2068 高数考试 
*/

#include<bits/stdc++.h> 
using namespace std;

const int MAX = 5e6+5;
int ary[MAX], sub[MAX];

int main( )
{
    
    
    // 录入数据 
    int n,p,x,y,z,minScore=MAX; 
	cin>>n>>p; 

    // 录入分数时同时记录差分数组 
    for(int i=1;i<=n;i++){
    
    
        cin>>ary[i];
        sub[i] = ary[i] - ary[i-1];
	}

	// 录入操作时只需要对差分数组进行修改 
    while(p--){
    
    
        cin>>x>>y>>z;
        sub[x] += z;
        sub[y+1] -=z;
	}

    // 还原数组并找出最小值 
    for(int i=1;i<=n;i++){
    
    
        ary[i] = ary[i-1] + sub[i];
        minScore = min(minScore, ary[i]);
	}

    // 输出最低分数 
	cout<<minScore<<endl;

    return 0;
}


MT2069 Arithmetic

Difficulty: Diamond Time limit: 1 second Memory usage: 256M
topic description

After learning the arithmetic sequence, Brother Xiaoma was refreshed. He wanted to find the arithmetic part in a long series of numbers.
He gives you an integer array nums, and requires the number of subarrays in the array that are arithmetic arrays (array array subarrays refer to consecutive numbers of at least 3 numbers forming an arithmetic array).

Format

Input format: an array of integers;
output format: a non-negative integer.

sample 1

Input: 1 2 3 4

Output: 3

Remark

The length of the array does not exceed 5000, and the range of elements is between -1000 and 1000.


Relevant knowledge points:前缀和与差分


answer


This question requires us to find the number of arithmetic subsequences in the specified sequence (the length of the subsequence is not less than 3).
Arithmetic sequence requires the same difference between each number, such as: { 1 , 2 , 3 , 4 } \{1, 2, 3, 4\}{ 1,2,3,4 } is an arithmetic sequence, and its difference array is{ 1 , 1 , 1 , 1 } \{1,1,1,1\}{ 1,1,1,1 } ; while{ 1 , 3 , 2 , 4 } \{1, 3, 2, 4\}{ 1,3,2,4 } is not, because its difference array is{ 1 , 2 , − 1 , 2 } \{1,2,-1,2\}{ 1,2,1,2 } . At the same time, there is another point to pay attention to in this question, such as the sequence{ 1 , 2 , 3 , 4 } \{1, 2, 3, 4\}{ 1,2,3,4 } , in fact, the sequence contains 3 arithmetic subsequences, which are:

  1. { 1 , 2 , 3 } \{1, 2, 3\} { 1,2,3}
  2. { 1 , 2 , 3 , 4 } \{1, 2, 3, 4\} { 1,2,3,4}
  3. { 2 , 3 , 4 } \{2, 3, 4\} { 2,3,4}

This can be obtained with a double loop during encoding. But in fact there is a rule here: for length nnThe sequence of n , the number of subsequences it contains is:1 + 2 + … + ( n − 1 ) = n ( n − 1 ) 2 1+2+\ldots+(n-1)\ =\frac{n( n-1)\ }{2}1+2++(n1) =2n(n1) . Therefore, in order to speed up the calculation, this formula can be directly used for calculation. But it should be noted that in this question, since the length of the subsequence is limited to not less than 3, we are getting a length of n ( n ≥ 3 ) n(n\geq3)n(n3 ) , the number of subsequences should be:1 + 2 + … + ( n − 2 ) = ( n − 1 ) ( n − 2 ) 2 1+2+\ldots+(n-2)= \frac{(n-1)(n-2)}{2}1+2++(n2)=2(n1)(n2)

To sum up the solution ideas:

  1. Enter data and build a differential array;
  2. Scan the differential array, when there are no less than 2 identical elements, it means that an arithmetic sequence has appeared currently. Next scan backwards through a pointer until it finds a value that is different from the element (or out of range of the array);
  3. Superimpose the number of current arithmetic subsequences: ( n − 1 ) ( n − 2 ) 2 \frac{(n-1)(n-2)}{2}2(n1)(n2)
  4. Output the number of all subsequences.

The following is the complete code (already AC) based on the above ideas:

/*
    MT2069 等差 
*/

#include<bits/stdc++.h> 
using namespace std;

const int MAX = 5e3+5;
int ary[MAX], sub[MAX];

int main( )
{
    
    
    // 录入数组内容的同时构建查分数组
    int num, index, n=0, ans = 0; 
    while(cin>>num){
    
    
        ary[++n]=num;
        sub[n] = ary[n] - ary[n-1];
    }

    // 遍历差分数组寻找等差数列
    // 显然,当差分数组中存在至少两个连续相同的数时,表明当前出现了等差数列
    for(int i=2;i<=n;i++){
    
    
        // 定义后向扫描指针 
        index = i+1;
        
        // 寻找与当前元素不同取值的元素位置 
        while(index<=n && sub[index]==sub[i]) ++index;
        
        // 计算并叠加当前序列中的所有等差子序列 
        ans += (index-i)*(index-i-1)/2;
        
        // 循环扫描指针跳跃(注:由于 for 循环里会执行 i++,因此这里跳跃 i 至 index-1) 
        i = (index-1);
    } 
    
    // 输出等差子序列个数
    cout<<ans<<endl;
    
    return 0;
}

END


Guess you like

Origin blog.csdn.net/the_ZED/article/details/130830839