[hihocoder 1249 Xiongnu's Land]线性扫描

2015区域赛北京赛区的三水,当时在赛场上没做出的原因是复杂度分析不正确导致把方法想复杂了。近来复习复杂度分析,觉得不能只是笼统地看渐进复杂度(big-O),更应根据算法的伪码计算真正的以基本操作数为变量的时间复杂度T(n)。

题意:在二维坐标系第一象限中,将一块顶点在原点边长为R的正方形土地用直线x=n一分为二,左侧分给Wei,右侧分给Huo。

土地中包含N个绿洲,每个绿洲是一个矩形,其位置和大小用四元组(L,T,W,H)表示,其中(L,T)为其左上方顶点的坐标,W,H为其宽度和高度。绿洲互不重叠。

求满足以下条件的一条划分直线(直线方程 x=n,0<=n<=R,n取整数):

(1)二人各自所得土地中绿洲面积应满足Wei>=Huo 且二者之差达到最小;

(2)在满足(1)的基础上,Wei的土地面积越大越好。

数据范围:1<=R<=1000000,    1<=N<=10000,     0<=L,T <=R,      1<=W,H<=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

按以上思路实现的代码,曾WA在long long类型,不应该~:

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 const int MAX_R = 1000005;
 5 const int MAX_N = 10005;
 6
 7 int K;
 8 int R, N;
 9 struct Rec{
10     int L, T;
11     long long W, H; //注意类型!!
12 }rec[MAX_N];
13 int x[MAX_R];
14
15 int main()
16 {
17     //freopen("in.txt","r",stdin);
18     //freopen("out.txt","w",stdout);
19     scanf("%d",&K);
20     while(K--){
21         scanf("%d",&R);
22         scanf("%d",&N);
23         memset(x,0,sizeof(x));
24         long long sum = 0;
25         for(int i=0; i<N; i++){
26             scanf("%d%d%d%d",&rec[i].L,&rec[i].T,&rec[i].W,&rec[i].H);
27             sum += rec[i].W*rec[i].H;
28             for(int j=rec[i].L; j<rec[i].L+rec[i].W; j++)
29                 x[j] += rec[i].H;
30         }
31         long long wei = 0;
32         int i;
33         for(i=0; wei*2 < sum; i++)
34             wei += x[i];
35         while(x[i]==0 && i<R) i++;
36         printf("%d\n",i);
37     }
38     return 0;
39 }

(若不可避免地1010的话,那么前面被否定的做法是否也可行呢,待续...)

[hihocoder 1249 Xiongnu's Land]线性扫描

时间: 2024-12-28 00:59:42

[hihocoder 1249 Xiongnu's Land]线性扫描的相关文章

[ An Ac a Day ^_^ ] HihoCoder 1249 Xiongnu&#39;s Land 线性扫描

拿到了icpc北京站的参赛名额 感谢亮哥~ 虽然是地狱之战 但也要全力以赴! 题意: 有一片沙漠 n片绿洲 让你用一条线分成两部分 左≥右 而且分割线要尽量靠右 问线的位置 思路: 网上说可以二分 没太看懂…… 还有一种思路就是线性扫描 将二维的图化成一维的线 然后从头扫一遍 遇到左≥sum/2时试探着向右继续扫 最后输出答案 1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #includ

15北京区域赛——A 二分——hihoCoder 1249 Xiongnu&#39;s Land

两次二分,第一次取得最小值,第二次往右二分看是否能到更右边 注意超出部分land部分要去掉 #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; struct edge{ int x, y, w, h; }a[10010]; bool cmp(edge A, edge B) { return A.x < B.x; } int n; ll cal(int x) { ll

hiho1249 Xiongnu&#39;s Land

题目链接:http://hihocoder.com/problemset/problem/1249 题目大意:有一个大正方形里面有好多不重叠的小矩形,怎么找出一条竖线分割这个正方形,使得两边的矩形面积尽量相等并且正方形左边的面积比右边大 思路:做两次二分就好了 1 #include <stdio.h> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 #define xx firs

UVALive-7261 Xiongnu&#39;s Land

题目链接 https://vjudge.net/problem/UVALive-7261 题面 Description 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 youn

[UVALive7261]A - Xiongnu&#39;s Land (二分)

题目链接:https://vjudge.net/problem/UVALive-7261 题意略 三个步骤: 1.二分满足左边绿洲面积大于等于右边绿洲面积,并且使左边面积尽可能大的分割线位置. 2.判断这个分割线是否包含于任何一个绿洲中,如果包含,那么直接输出结果就行,否则: 3.从此坐标向右扫描,找到下一个绿洲的左边界,此为答案. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 typ

[Android游戏开发学习笔记]View和SurfaceView

本文为阅读http://blog.csdn.net/xiaominghimi/article/details/6089594的笔记. 在Android游戏中充当主要角色的,除了控制类就是显示类.而在Android中涉及到显示的是View类,及继承自它的SurfaceView类和SurfaceView的其他子类等. 这里先只说View和SurfaceView.SurfaceView的直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及CAmera摄像头一般均使用Su

UVALive 7261 Xiongnu&#39;s Land(二分)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5273 思路:二分位置(无需考虑总坐标,仅考虑横坐标即可),使得2*area >= sum,在满足该条件的情况下,尽量右移使得左侧面积尽量大. #include<cstdio> #include<cstring> #include<

2015北京区域赛 Xiongnu&#39;s Land

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

【CF676C】Vasya and String(二分查找,线性扫描尺取法)

题意: 给出一个长度为n的字符串,只有字符'a'和'b'.最多能改变k个字符,即把'a'变成'b'或把'b'变成'a'. 问改变后的最长连续相同字符的字串长度为多少. 首先是二分查找,好想也好写 1 var s:array[0..100000]of longint; 2 ch:ansistring; 3 n,k,i,l,r,mid,last,ans:longint; 4 5 function max(x,y:longint):longint; 6 begin 7 if x>y then exit