Wei Qing (died 106 BC) was a military general of the Western Han dynasty whose campaigns against the Xiongnu earned him great acclaim. He was a relative of Emperor Wu because he was the younger half-brother of Empress Wei Zifu (Emperor Wu’s wife) and the husband of Princess Pingyang. He was also the uncle of Huo Qubing, another notable Han general who participated in the campaigns against the Xiongnu and exhibited outstanding military talent even as a teenager.
Defeated by Wei Qing and Huo Qubing, the Xiongnu sang: “Losing my Qilian Mountains, made my cattle unthriving; Losing my Yanzhi Mountains, made my women lacking rouge.”
The text above is digested from Wikipedia. Since Wei and Huo’s distinguished achievements, Emperor Wu decided to give them some awards — a piece of land taken by them from Xiongnu. This piece of land was located in a desert, and there were many oases in it. Emperor Wu wanted to draw a straight south-to-north dividing line to divide the land into two parts, and gave the western part to Wei Qing while gave the eastern part to Huo Qubing. There are two rules about the land dividing:
1. The total area of the oases lay in Wei’s land must be larger or equal to the total area of the oases lay in Huo’s land, and the difference must be as small as possible.
2. Emperor Wu wanted Wei’s land to be as large as possible without violating the rule 1
To simplify the problem, please consider the piece of land given to Wei and Huo as a square on a plane. The coordinate of its left bottom corner was (0, 0) and the coordinate of its right top corner was (R, R). Each oasis in this land could also be considered as a rectangle which was parallel to the coordinate axes. The equation of the dividing line was like x = n, and n must be an integer. If the dividing line split an oasis, then Wei owned the western part and Huo owned the eastern part. Please help Emperor Wu to find out how to draw the dividing line.
Input
The first line of the input is an integer K meaning that there are K (1 ≤ K ≤ 15) test cases.
For each test case:
The first line is an integer R, indicating that the land’s right top corner was at (R, R) (1 ≤ R ≤ 1, 000, 000)
Then a line containing an integer N follows, indicating that there were N (0 < N ≤ 10000) oases.
Then N lines follow, each contains four integers L, T, W and H, meaning that there was an oasis whose coordinate of the left top corner was (L, T), and its width was W and height was H. (0 ≤ L, T ≤ R, 0 < W, H ≤ R). No oasis overlaps.
Output
For each test case, print an integer n, meaning that Emperor Wu should draw a dividing line whose equation is x = n. Please note that, in order to satisfy the rules, Emperor might let Wei get the whole land by drawing a line of x = R if he had to.
Sample Input
2
1000
2
1 1 2 1
5 1 2 1
1000
1
1 1 2 1
Sample Output
5
2
题意:有多个矩形分布在[0, 0]到[R, R]的的范围内。 画一条竖线分割成两块矩形,使得左边包括矩形的面积大于等于右边的面积。 在这个前提下使得画的竖线尽量远。
题解:复杂度分析:从所给数据范围看,R在106数量级,既然n取[0,R]的整数,那么若以R为数据规模,对x=i, i:0~R进行步长为1的线性扫描,假设每次迭代中基本操作次数为常数,则渐进复杂度为O(n)。 假设计算环境1000ms的时间可完成108规模的基本运算,则本题O(n)的线性扫描思路从渐进复杂度的意义上讲是可行的。 确定了线性扫描的思路,接下来要考虑如何把每轮迭代代价控制在常数以及扫描停止的条件。 1. 如果在每轮迭代中,都检查所有N个绿洲以求出所划分的面积,那么每轮迭代的复杂度为T(N),整体复杂度上升到了T(N*R), 即1010显然不可行。 此方法的低效在于它没有为线性扫描这一“算法”设计合适的“数据结构”来存放绿洲的数据。 题目输入的绿洲是一个个分散的个体,而从坐标出发的线性扫描需要快速获得以扫描位置 x=i 为自变量的左侧累加面积,这一“快速”,常数最好,至少不能和N在同一数量级。 因此,要进行预处理将原始的绿洲数据转换为以横坐标为中心的统计值,以使每次迭代能用1~2个基本操作得到当前累加面积进而判断下一步的走向。 2. 扫描可以从最左侧的x=0开始,不断向右移动(保证绿洲面积左侧 < 右侧)。 遇到第一个理想位置(左侧>=右侧,满足了(1))后继续试探,直至抵达最理想的位置(左侧绿洲面积不增的条件下,为满足(2)尽量再往右移动)停止。 由于扫描是线性的,可利用一个累加变量,每次只取当前“列”的面积作累加即可。 至此,对绿洲数据的预处理结果要求已经比较明确了。 即得到 x=i 代表的一段宽度为1(可以是i ~ i+1),高度为R的土地中绿洲的总面积,不妨用x[i]表示。 那么这段预处理所花费的时间呢,这回要以N为数据规模来考虑,假设所有绿洲被读入结构体数组中,则对j:0~N-1进行步长为1的线性扫描,假设每次迭代中基本操作次数为常数,N在104数量级,完全可行。 但处理每个绿洲真的是常数时间吗,其实应该是T(W),因为要把宽度切分为长度为1的W段,累加到x数组的W个元素上。除非x用的不是朴素的一维数组,否则整体的渐进复杂度应为O(N*W),又是1010。
#include <cstdio> #include <cstring> using namespace std; const int MAX_R = 1000005; const int MAX_N = 10005; int K; int R, N; struct Rec{ int L, T; long long W, H; //注意类型!! }rec[MAX_N]; int x[MAX_R]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); scanf("%d",&K); while(K--){ scanf("%d",&R); scanf("%d",&N); memset(x,0,sizeof(x)); long long sum = 0; for(int i=0; i<N; i++){ scanf("%d%d%d%d",&rec[i].L,&rec[i].T,&rec[i].W,&rec[i].H); sum += rec[i].W*rec[i].H; for(int j=rec[i].L; j<rec[i].L+rec[i].W; j++) x[j] += rec[i].H; } long long wei = 0; int i; for(i=0; wei*2 < sum; i++) wei += x[i]; while(x[i]==0 && i<R) i++; printf("%d ",i); } return 0; }