[Horseshoe Collection] Homework for the eighth week

Eighth week homework






Median of MT2016 data stream

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

For the data flow problem, Brother Xiaoma needs to design an online system that continuously receives some data and maintains some information about the data.

The median is the number in the middle of an ordered list. If the list length is even, the median is the average of the middle two numbers.

Please help me design a system that supports the following two operations:

  • + num Add an integer k from the data stream to the system ( 0 < k < 2 32 0<k<2^{32}0<k<232 )。

  • ? Returns the median of all elements so far.

Format

Input format: input an integer n ( n ≤ 100000 ) n(n≤100000) in the first linen(n100000)

     Enter nn on the second linen operands.

Output format: ? Output the median when inquiring, one line for each operation, to ensure that each query is legal.

sample 1

Input: 5

   + 1

   + 2

   ?

   + 3

   ?

Output: 1.5


Relevant knowledge points: 模拟


answer


The requirements of the topic are very simple. There is a system that asks two types of queries: one is to add data, and the other is to output the median of the existing sequence. Our task is to execute all instructions of the system. This is an obvious mock question.

Based on this, we can define an array. Whenever the system requires to increase data, the method can be 选择排序used to perform insertion to maintain the order of the array; whenever the system requires to output the median, the median can be found according to the length of the current array. This is the most simple and direct way, but it must time out. Because for an insert data request: the time complexity of selecting the insertion position and adjusting the element position in the array is O ( n ) O(n)O ( n ) , so fornnFor n times of inserting data requests, its time complexity will reachO ( n 2 ) O(n^2)O ( n2 ). The maximum number of insertion operations for the topic can be up to 100000, so this will inevitably time out.


Method 1: Use multiple collections

From the above analysis, we can see that the core of solving this problem is 如何加速动态插值过程中的排序过程that it is not difficult for us to think of using some containers with quick sorting function.

set(集合)It is a container that stores elements in a certain order (default ascending order), and the elements in it are always sorted according to the specific criteria indicated by its internal comparison object (type comparison). Its underlying data structure is 红黑树, so its time complexity is O ( log 2 n ) O(log_2n) both for a single query and for inserting elements (to build an ordered container)O(log2n ) . (Note: In order to maintain this order, the elements in the set cannot be modified, but can only be deleted and reinserted). So for set, in the face ofnnWhen inserting data requests n times (while keeping the container in order), its time complexity isO ( nlog 2 n ) O(nlog_2n)O ( n l o g2n ) . This is acceptable. But one problem with set is that the elements it contains must be unique. However, the data inserted in the topic does not necessarily meet this condition, so we have to think about other data structures.

So, multiset(多重集合)it came into our field of vision. Multiset is almost the same as set in terms of implementation and function, the main differences are:

  • Elements in multiset can be repeated, but elements in set must be unique;
  • Multiset stores <value, value> key-value pairs at the bottom layer, while set stores value;

Note that the elements in the multiset can be repeated, which is exactly what we need.

However, there is a problem with set and multiset as associative containers: elements cannot be accessed through subscript indexes, and corresponding iterators or pointers must be used. Since the multiset cannot use the index to access the elements, we have to find another way when taking the median (here we must not directly iterate the query, because the time complexity of the iterative query is O ( n ) O(n )O ( n ) , then fornnThe time complexity of n queries reachesO ( n 2 ) O(n^2)O ( n2))。

The following is a "pointer fixation" method to make the two pointers (left pointer l and right pointer r) point to the middle number when the number of current containers is odd; when the number of current containers is even, They point to the two middlemost numbers respectively. The following process accepts one input data at a time:

  1. Get the size of the number of elements in the current container;

  2. The container inserts the current input data num;

  3. If size=0, point the left and right pointers to the top element of the container;

  4. If the size is an odd number (it means that the current left pointer l and right pointer r point to the same position, and the size will become even after inserting num), then judge the location pointed to by num and the left pointer l (you can also choose the right pointer r) The size of the data (to determine the insertion position of num):

    • If num<*l, it means that after num is inserted into the current container (and sorted), num is in front of the data pointed to by the left pointer l, so the left pointer l needs to be moved forward by one unit.
    • Otherwise, it means that after inserting num (and sorting) into the current container, num is behind the data pointed to by the left pointer l (and right pointer r), so it is necessary to move the right pointer r backward by one unit.
  5. If size is an even number (it means that the current left pointer l and right pointer r point to different positions, and the size will become odd after inserting num), then it is necessary to judge the size of num and the data pointed to by left pointer l and right pointer r ( to determine the insertion position of num):

    • If *l < num < *r, it means that after the current container is inserted into num (and sorted), num is between the left and right pointers, and num is the median of the current (ordered) container. Therefore, it is necessary to move the left pointer l backward by one unit, and the right pointer r forward by one unit (at this time, the left and right pointers actually point to the same address).
    • If num<=*l, it means that after the current container is inserted into num (and sorted), num is before the data pointed to by the right pointer r. At this time, the previous bit of the data pointed to by the right pointer r is the current (ordered) container median. Therefore, it is necessary to move the right pointer r forward by one unit (at this time, the data it points to must be the median); for the left pointer l, since num is equal to *l, it is impossible to determine which one the pointer points to, so directly Just let l=r.
    • Otherwise, it means that after the current container is inserted into num (and sorted), num is behind the data pointed to by the left pointer l. At this time, the previous bit of the data pointed to by the left pointer l is the median of the current (sorted) container. Therefore, it is necessary to move the left pointer l back by one unit (at this time, the data it points to must be the median); for the right pointer r, since num is equal to *r, it is impossible to determine which one the pointer points to, so directly Just let r=l.

Through the above steps, it can be guaranteed that each time data is inserted, the left pointer l and right pointer r point to the median of the ordered array: when the length of the array is odd, l=r=midPosition; when the length of the array is even, l and r respectively point to the median the middle two numbers. At the same time, the statement that takes the median value can also be obtained as: (*l + *r) / 2.0.

Based on the above ideas, the complete code to solve this problem can be written as (AC):

/*
	数据流的中位数 
	 
	方法一:利用多重集合
*/

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

// 定义多重集合 
multiset<long> s;

// 定义左指针和右指针(初始指向end) 
multiset<long>::iterator l = s.end(), r = s.end();
 
// 定义插值函数 
void addNum(long num) {
    
    
	// 获取当前多重集合的长度 
    int size = s.size();
    
    // 将数据插入多重集合 
    s.insert(num);
    
    // 插入第一个元素
    if(size == 0) l = r = s.begin();
    
	// 若 size 为奇数(则在插入元素后,size 将变为偶数,即两个指针会指向不同地址) 
    else if(size & 1){
    
    
    	
    	// 若插入的数比左指针指向的数据还小,则左指针前移 
        if(num < *l) l--;
        
        // 否则右指针前移 
        else r++;
    }
    
    // 若 size 为偶数(则在插入元素后,size 将变为奇数,即两个指针会指向同一地址)
    else{
    
    
    	
    	// 若插入的数值处于左、右指针指向的数据之间,则该位置就是中位数(左指针后移,右指针前移) 
        if(num > *l && num < *r){
    
    
            l++;
            r--;
        }
        
        // 若插入的数值不大于左指针指向的数据,则右指针前移,并将左指针指向右指针指向的位置 
        else if(num <= *l){
    
    
            r--;
            l = r;
        }
        
        // 否则表示插入的数值不小于右指针指向的数据,则左指针后移,并将右指针指向左指针指向的位置 
        else{
    
    
            l++;
            r = l;
        }
    }
}


// 获取中位数 
float getMedian() {
    
    
    return (*l + *r) * 0.5;
}
 

int main() {
    
    
	// 录入数据 
	char opt;
	long tmp;
    int n;cin >> n;
    
    while(n--) {
    
    
        cin>>opt;
        
        // 基于 opt 分别予以答复 
        switch(opt){
    
    
        	case '+':
        		cin>>tmp;
        		addNum(tmp);
        		break;
        		
        	case '?':
        		cout<<getMedian()<<endl;
        		break;
		}
    }
 
    return 0;
}

Method 2: Use the heap

Equivalent existence sequence A = { ai , i = 1 , 2 , … } A = \{ a_i , i=1,2,… \}A={ ai,i=1,2,} , think carefully about the nature of the median (for ease of understanding, assume that the number of elements in the sequence is odd): If there is a medianamid a_{mid}amidThen for any i < mid i<midi<mid d都有ai ≤ amid a_i≤a_{mid}aiamid;Similarly, for any mid < j mid<jmid<j Touamid ≤ aj a_{mid}≤a_jamidaj. That is, if the sequence AAA is divided by the median to getA 1 A_1A1Sum A 2 A_2A2Two series, the median must satisfy:

a m i d ≥ m a x ( A 1 ) a m i d ≤ m i n ( A 2 ) a_{mid} ≥ max(A_1) \\ a_{mid} ≤ min(A_2) amidmax(A1)amidmin(A2)

Based on this property, we can maintain two heaps whose lengths differ by no more than 1 (requiring that all the numbers in heap A are smaller than the numbers in heap B). Next, heap A is designed as a large-rooted heap, and heap B is designed as a small-rooted heap. This way, only the lengths of the two heaps need to be compared when outputting the median:

  • If the lengths are equal, it means that the number of numbers in the current system is even, and the median at this time is the sum of the middle two numbers divided by 2. That is: take out the top elements from the two heaps, sum and divide by 2.
  • If the lengths are not equal, it means that the number of numbers in the current system is odd, so it depends on whose length is longer? The top element of the longer heap is the median in the current system.

Then how to ensure the aforementioned requirement: all the numbers in the heap A are smaller than the numbers in the heap B?

It is very simple. Every time data num is inserted into the heap, the size relationship between num and the current system median Nmid is judged in advance, so as to decide which heap to insert it into. But there is one thing to note, we must maintain that the length difference between the two heaps does not exceed 1! Therefore, the specific control flow is as follows:

  • If the length of the current heap A is equal to the length of the heap B (that is, the number of data in the current system is an even number), then further judge: if num < Nmid, then insert num into the heap A; otherwise, insert it into the heap B.
  • If the length of the current heap A is less than the length of the heap B, it means that the median of the current system is in the heap B. At this point, compare the size of num and the top element (ie, the median) of heap B:
    • If num<=Nmid, insert num into heap A;
    • Otherwise, remove the top element from heap B, insert the top element into heap A, and then insert num into heap B.
  • If the length of the current heap A is greater than the length of the heap B, it means that the median of the current system is in the heap A. At this point, compare the size of num and the top element (ie, the median) of heap A:
    • If num>=Nmid, insert num into heap B;
    • Otherwise, take the top element from heap A, insert the top element into heap B, and then insert num into heap A.

In this way, it can always be guaranteed that "all the numbers in heap A are smaller than the numbers in heap B".

Based on the above ideas, the complete code to solve this problem can be written as (AC):

/*
	数据流的中位数 
	 
	 方法二:利用堆
*/


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

// 定义两个优先队列:其中 A 队列中的所有元素取值都小于 B 
// 队列 A 为大根堆 
priority_queue<long, vector<long>, less<long> > A; 
 
// 队列 B 为小根堆 
priority_queue<long, vector<long>, greater<long> > B; 


// 获取中位数 
float getMedian() {
    
    
	// 队列 A、B  长度相等,则取各堆顶元素求和再除以 2 
    if(A.size() == B.size()) return (A.top()+B.top()) * 0.5;
	
	// 长度不等,则返回堆长度更长的那一个
	return (A.size() > B.size())?A.top():B.top(); 
}

// 定义插值函数 
void addNum(long num) {
    
    
    // 若两个队列的长度相等,则进一步比较 num 与中位数的大小关系 
    if(A.size() == B.size()){
    
    
    	
    	// 初始情况下默认插入第一个堆 
    	if(A.size() == 0){
    
    
    		A.push(num);
    		return;
		}
    	
    	// 判断大小 
    	if(num < getMedian()) A.push(num);
    	else B.push(num);
    }
	
	// 若堆 A 的长度小于堆 B 的长度,则进一步比较 num 与堆 B 的堆顶元素(即中位数)大小 
	else if(A.size() < B.size()){
    
    
		if(num <= B.top()) A.push(num);
		else{
    
    
			A.push(B.top());
			B.pop();
			B.push(num);
		}
	} 
	
	// 若堆 A 的长度大于堆 B 的长度,则进一步比较 num 与堆 A 的堆顶元素(即中位数)大小 
	else{
    
    
		if(num >= A.top()) B.push(num);
		else{
    
    
			B.push(A.top());
			A.pop();
			A.push(num);
		}
	} 
}


 
int main() {
    
    
	// 录入数据 
	char opt;
	long tmp;
    int n;cin >> n;
    
    while(n--) {
    
    
        cin>>opt;
        
        // 基于 opt 分别予以答复 
        switch(opt){
    
    
        	case '+':
        		cin>>tmp;
        		addNum(tmp);
        		break;
        		
        	case '?':
        		cout<<getMedian()<<endl;
        		break;
		}
    }
 
    return 0;
}


MT2017 Continuous String

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

Given a string, find the most frequently occurring substring of length 2.

Format

Input format: the first line is a positive integer n, indicating the length of the given string, and the second line is a string.

Output format: output the requested string, if there are multiple results, output the one with the smallest lexicographical order.

sample 1

Input: 7

   They are not flat

Output: AB

Remark

Where: 2 ≤ n ≤ 100 2≤n≤1002n100 ; contains only uppercase letters in the string.


Relevant knowledge points:模拟


answer


This question is a very basic simulation question, and its data range is also small, so the solution idea is to solve it by brute force method traversal (use map to construct a mapping from strings to occurrences). One thing to note in this question is that when constructing a map object, strings cannot be of char *type . Because when map is building key-value, if your string is used char *, no matter how many different keys you create, there will be only one key in the map in the end, that is the last one you created (the last char *pointed address).

Another detail is about the choice of data structure. Since this question requires "if there are multiple results, output the smallest lexicographical order", it actually implies that the data structure you use should be in order of strings. Therefore, it cannot be selected simply because of the pursuit of speed unordered_map.

The complete code to solve this problem is given directly below

/*
	连续的串 
	 
*/


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

const int LIMIT = 2;
map<string, int> m;

void getMaxRepeat(string str){
    
    
	// 定义临时字符串容器 
	string tmp;
	
	// 统计不同子串的个数(且子串要按字典序排序) 
	for(int i=0; i<str.length()-LIMIT+1; i++){
    
    
		// 取长度为 LIMIT 的子串并存进 tmp 中 
		tmp = str.substr(i,LIMIT);

		// 为此键值的出现次数 +1 
		m[tmp]++;
	}
	
	// 定义临时最长出现次数 
	int maxRepeat = 0;
	
	// 遍历 map 寻找所有子串出现次数中的最大值 
	for(auto iter : m){
    
    
		if(iter.second > maxRepeat){
    
    
			maxRepeat = iter.second;
			tmp = iter.first;
		}
	}
	
	cout<<tmp<<endl;
}

int main( )
{
    
    
	// 获取输入 
	int n; cin>>n;
	string str; cin>>str;
	
	// 输出操作次数
	getMaxRepeat(str);
	 
    return 0;
}


MT2027 One second becomes zero

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

Given a positive integer nn , please write a functionSteps StepsStep s , thenn _n becomes 0 by the following operations, and the number of operations is returned.

n n n is an even number, thenn = n / 2 n=n/2n=n/2

n nn is an even number, thenn = n − 1 n=n-1n=n1

Format

Input format: input positive integer n in the first line.

Output format: Output the number of operations.

sample 1

Input: 14

Output: 6

Remark

Where: 1 ≤ n ≤ 1 0 7 1≤n≤10^71n107


Relevant knowledge points:模拟


answer


There is nothing to say about this question, just a pure simulation:

Either recursion or recursion, but in view of the data range, I still think recursion is more appropriate.


/*
	一秒成零
	
*/


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

// 递推实现(数的取值范围较大时) 
int Steps(int n){
    
    
	
	// 定义操作次数 
	int optCnt = 0;
	
	// 开始递推 
	while(n){
    
    
		
		// 当前为奇数时:
		if(n&1) n--;
		
		// 否则为偶数时:
		else n/=2;
		
		// 操作次数 +1 
		optCnt++;
	}
	return optCnt;
} 

// 递归实现 
int Steps_(int n){
    
    
	
	// 终止条件
	if(n==0) return 0; 
	
	// 当前为奇数时: 
	if(n&1) return Steps(n-1)+1;
	
	// 否则为偶数时: 
	return Steps(n/2)+1; 
} 

int main( )
{
    
    
	// 获取输入 
	int n; cin>>n;
	
	// 输出操作次数
	cout<<Steps(n);
	 
    return 0;
}


MT2033 Bumper Car

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

Amusement parks play with bumper cars, and one of them runs in a straight line. The bumper car has an initial orientation and initial position, and it moves forward in the initial direction at a speed of one unit per second. When it meets other bumper cars, they will turn around immediately (due to the high speed, the turning time can be ignored). Can you figure out where they will be after t seconds?

Format

Input format: the first line has two numbers n ( 1 − 100 ) , t ( 0 − 100 ) n (1-100),t (0-100)n(1100),t(0100 ) , which respectively represent: the number of bumper cars and the time used; nextnnn lines, each with two numbers:x , fx,fx,f represent thennthThe position and direction of n bumper cars (0 ≤ x ≤ 1 0 5 0≤x≤10^50x105 , -1 means left, 1 means right).

Output format: output nnN lines, two numbers in each line, respectively represent the final position and direction of the bumper car (-1 means left, 1 means right, 0 means two cars meet).

sample 1

Input: 5 2

   4 1

   5 -1

   7 1

   2 1

   6 -1

Output: 4 0

   4 0

   9 1

   3 -1

   6 1


Relevant knowledge points:模拟


answer


To solve this problem, we must realize the following two key points:

  1. For any bumper car, no matter how many collisions and how long it takes, its relative position is always fixed. For example, for the example given in the title, no matter how much time has elapsed, the iiCar i will always be in position iii positions. This gives us an idea of ​​how to arrange the original bumper cars (how to restore the bumper cars after processing).

bumper car

  1. If the differences between all bumper cars are not considered (i.e., all cars are the same), and it is assumed that these cars will not collide (i.e., assuming that there is currently nnn lanes), in this case, the position of all cars after any time is actually consistent with the state they will get when they collide.

Do not touch the car

Based on the above two characteristics, we can conclude that if the driving state simulation of "no difference and no collision" is carried out for all the bumper cars, in the final state obtained by the simulation, the mapping relationship between the relative position of each bumper car and its absolute position is consistent with the "some The mapping relationship is consistent in the case of "differences collide". Therefore, we can cleverly obtain the final position of each bumper car through this mapping relationship. Its establishment process is as follows:

  1. Save the bumper car sequence entered at the beginning into an array (this is the absolute position). For example, in the example above, the sequence of bumper cars given in the title is:
  • Data 1: orange car
  • Figure 2: Green car
  • Data 3: black car
  • Figure 4: blue car
  • Data No. 5: Yellow car
  1. Sort by the actual position of each car, and get their relative position:
  • 1st data: blue car (position: 2)
  • 2nd piece of data: orange car (position: 4)
  • 3rd data: green car (position: 5)
  • 4th data: yellow car (position: 6)
  • 5th data: black car (position: 7)
  1. Based on this, the mapping relationship from relative position to absolute position can be established as:
    { 1 → 4 , 2 → 1 , 3 → 2 , 4 → 5 , 5 → 3 } \{ 1 \rightarrow 4, 2 \rightarrow 1, 3 \rightarrow 2, 4 \rightarrow 5, 5 \rightarrow 3 \}{ 14,21,32,45,53}

  2. Next, without considering the differences and collisions of each car, directly traverse all the cars in 2, and simulate the driving of each car:

  • The first car (blue), the position after driving t seconds: 4
  • 2nd car (orange), position after t seconds of driving: 6
  • The 3rd car (green), the position after driving t seconds: 3
  • The 4th car (yellow), the position after driving t seconds: 4
  • The 5th car (black), the position after driving t seconds: 9
  1. Next, sort according to the actual position of each car again, which will generate a new relative position (note that although some cars have the same position, when they are arranged in the array, their indexes must be different, but no matter which index is bigger or smaller , neither affect the final output):
  • Position 1: Position 3 (Green)
  • Position 2: Position 4 (blue)
  • Position 3: Position 4 (yellow)
  • Position 4: Position 6 (orange)
  • Position 5: Position 9 (black)
  1. Then, according to the "relative position to absolute position mapping" table stored earlier, the relative position pair obtained above can be converted into an absolute position:
  • The first bit (1→4), so it is the fourth output (position: 3)
  • The 2nd bit (2→1), so it is the 1st output (position: 4)
  • The 3rd bit (3→2), so it is the 2nd output (position: 4)
  • The 4th bit (4→5), so it is the 5th output (position: 6)
  • The 5th digit (5→3), so it is output as the 3rd one (position: 9)
  1. Finally, in order to ensure that the output order is consistent with the input, we arrange all the data according to their absolute positions and output, that is:
  • Line 1: 4
  • Line 2: 4
  • Line 3: 9
  • Line 4: 3
  • Line 5: 6

According to this idea, the following methods can be used to calculate the final position of the bumper car:

  1. Design a structure Car, which contains the current bumper car input 序号(index)(indicating the input order of each bumper car as an absolute position), 位置(position)and 方向(direction). Then you can build an array through this structure to store all the input information: namely Car cars[MAX];
  2. From key point 1, it can be seen that no matter how the bumper cars move, their relative positions will not change, so we first need to sort them according to the position of the bumper cars, so that the relative positions of all the bumper cars can be determined (at this time, the relative positions are passed sorted cars[] array index indication);
  3. Next, traverse the sorted cars array to establish the mapping relationship from relative position to absolute position. At the same time, it is necessary to change the state of each bumper car in it (ignoring collisions and differences between cars). Here we use the information of key point 2: "If you ignore the collision between the cars and let them keep driving, the final position of each car is consistent with the situation that is not ignored";
  4. Then, 位置(position)sort the cars array again according to the attributes. At this time, the index of the cars array is obtained by sorting, which is the new relative position of each car under the premise of "ignoring the collision between cars". And key point 2 tells us that the mapping relationship between the relative position obtained here and the absolute position in the real situation (considering collision) is unchanged. That is to say, the "index mapping" established earlier can be used to restore the bumper cars at each relative position 序号(index).
  5. Finally, since this question requires the bumper cars to be output according to the specified input order (that is, the question considers that there are differences between cars), we can sort the cars array again with 序号(index)the attribute Output the sorted cars array in order to get the desired answer.

The following is the complete code written according to the above ideas:

/*
	碰碰车
	 
*/


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

const int MAX= 1005;
struct Car{
    
    
	int position, direction, index;
};
Car cars[MAX];
int indexArray[MAX];

bool cmp1(Car c1, Car c2){
    
    
	return c1.position<c2.position;
}

bool cmp2(Car c1, Car c2){
    
    
	return c1.index<c2.index;
}

int main( )
{
    
    
	// 获取输入 
	int n, t;cin>>n>>t;
	for(int i=0;i<n;i++){
    
    
		cin>>cars[i].position>>cars[i].direction;
		cars[i].index = i;
	}
	
	// 按位置排序(以获取各车的相对位置) 
	sort(cars, cars+n, cmp1); 
	
	// 模拟碰碰车的行驶过程(忽视碰撞)并记录相对位置 
	for(int i=0;i<n;i++){
    
    
		
		// 记录各车相对位置到绝对位置的映射 
		// 数组 indexArray 的索引是某个车的相对位置;存储值为该相对位置对应的绝对位置
		indexArray[i] = cars[i].index;
		
		// 开车开车
		cars[i].position += cars[i].direction*t;
	} 
	
	// 再次按位置排序,得到各车行驶 t 秒后的相对位置(此值被 cars 数组的索引指示) 
	sort(cars, cars+n, cmp1);
	
	// 根据相对位置到绝对位置的映射记录来还原各车的绝对位置
	for(int i=0;i<n;i++){
    
    
		
		// 还原各车的绝对位置
		cars[i].index = indexArray[i]; 
		
		// 注意将那些“相撞”的车的方向置为 0
		if(i>0 && cars[i].position==cars[i-1].position ||
		 i<n-1 && cars[i].position==cars[i+1].position) 
		 	cars[i].direction = 0;
	} 
	
	// 按绝对位置排序
	sort(cars, cars+n, cmp2); 
	
	// 输出
	for(int i=0;i<n;i++) cout<<cars[i].position<<" "<<cars[i].direction<<endl; 
	 
    return 0;
}


MT2036 Moving Water to Create the Sea

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

Today, the boring little code brother opened his tr, and he suddenly thought, "I want to fill a continent in a new world with buckets of water to fill the sea", although this idea is boring, but he really did it.

Because Xiaoma used the modifier, he has unlimited buckets. A bucket of water can just fill a grid. But if the water level is higher than the land on one side after pouring the water, then the water will overflow, and this bucket of water is equivalent to not being poured.
In addition, the left and right sides of the world are empty spaces, and water will disappear when it touches the empty space.

Now you are given a topographic map of this world, tell you the width n of this world and the height h of each column of land, and ask you how many buckets of water you need at least to fill this world (to fill is to pour a bucket of water wherever will overflow).

Format

Input format: the first line is a positive integer n ( n ≤ 10000 ) n(n≤10000)n(n10000 ) , representing the width of the world (this is a world);

     Enter nn on the second linen non-negative integerhi h_ihi, indicating the iiHeight of column i land

Output format: an integer, indicating at least how many buckets of water are needed.

sample 1

Input: 6

   3 0 2 0 1 0

Output: 3

Sample 2

Input: 5

   1 0 0 0 1

Output: 3

Example 3

Input: 9

   4 1 2 3 6 3 2 1 3

Output: 9

Remark

Where: 3 ≤ n ≤ 10000 , 0 ≤ h ≤ 10000 3≤n≤10000,0≤h≤100003n10000,0h10000


Relevant knowledge points:模拟


answer


After interpreting the topic, it can be described as: filling the "mountain" in the two-dimensional world. For example, the figure below shows the third example given in the title:

insert image description here

The grids that can be filled with water are as follows (9 in total):

insert image description here

Our task is to output the corresponding number of grids that can be filled with water for the "mountain" of any shape given in the title. Note one thing, the grid that can be used for water filling should satisfy: the height of the peak in the vertical direction of the grid is lower than the height of the peaks on its sides (this will form a gap). Therefore, we need to design an algorithm to detect and count the number of gaps in the "mountain" of the specified shape.

An intuitive way is to scan from bottom to top and from left to right. Since it is necessary to scan in a specified direction, it is necessary to determine the upper and lower limits of the scan pointer. When scanning from bottom to top, the purpose is to obtain the peak height in the current vertical direction, so as to facilitate comparison. Obviously, the maximum value of the peak height is the maximum value of all peak heights in the input data, and the minimum value is 0; when scanning from left to right, its range is exactly the range of the input "land height" sequence. In addition, we must also pay attention to one point: "the left and right sides of the world are void, and the water will disappear when it touches the void." That is to say, for the left and right sides of a column in the "mountain", a gap must also be formed (high on both sides and low in the middle). So when we scan from left to right, we need to find a way to detect the appearance of "gap".

Notice the characteristic of the "gap": the height of the mountain at the current location is lower than its left and right sides. Therefore, we can set a "last height pointer lastHeighter" whose record is higher than the "current layer height mtHeight" to temporarily store the left peak position of the gap. Next, traverse the height of each input mountain horizontally, and judge whether it is greater than lastHeighter in turn? If yes, it means that one (or several) "gap" is currently found. Based on this idea, the algorithm flow can be described as follows:

  1. (Longitudinal) traverse the height of the mountain: 0~maxHeight (the highest peak in the mountain), set lastHeighter=-1 at the beginning of each cycle, indicating that there is no gap condition by default in the initial situation (description "Water will disappear when it touches the void" this situation).
  2. (Horizontal) traverse all peaks: if the current peak height height[j] is greater than the current layer height mtHeight, it means that the right peak of the gap has been found, that is to say, there is a "gap". But wait! It is also necessary to judge whether the pointer lastHeighter of the last higher peak position exists. If it exists (that is, its value is not -1), it means that there is a "gap"; otherwise, it does not. When there is a "gap", there may be multiple in between, and its number = "gap right pointer" - "gap left pointer" - 1. Right now:

"gap" amount = j - lastHeighter - 1

Finally, the new "higher peak position" that appears here also needs to be updated to lastHeighter.

Based on this idea, the complete code for solving this problem can be obtained:

/*
	移水造海 
	 
*/


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

const int MAX= 10005;
int ary[MAX];

// 获取数组中的最大值 
int getArrayMax(int ary[], int n){
    
    
	int max = ary[0];
	for(int i=1; i<n; i++)
		if(ary[i] > max)
			max = ary[i];
	return max;
}

// 计算需要的水桶数量
int getBuckets(int ary[], int n){
    
    
	int bukets = 0, maxHeight = getArrayMax(ary,n), last;
	
	// 从最底层开始往上逐层扫描 
	for(int i=1; i<=maxHeight; i++){
    
    
		// 每次初始化标记上一次的层高
		last = -1;
		
		// 接下来从左往右扫描
		for(int j=0; j<n; j++)
			if(ary[j] >= i){
    
    
				if(last != -1) bukets += (j-last-1);
				
				// 更新上一次的层高 
				last = j;
			} 
	} 
	
	return bukets;
} 

int main( )
{
    
    
	// 获取输入 
	int n; cin>>n;
	for(int i=0;i<n;i++) cin>>ary[i];
	
	// 输出操作次数
	cout<<getBuckets(ary,n);
	 
    return 0;
}

END


Guess you like

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