[杂题] pku 2019

来源:互联网 发布:java就业培训中心 编辑:程序博客网 时间:2024/04/27 23:58

解题报告: Cornfields Lcftc 题目类型:搜索,简单,PKU2019题 一、 题目: Cornfields Description FJ has decided to grow his own corn hybrid in order to help the cows make the best possible milk. To that end, he's looking to build the cornfield on the flattest piece of land he can find. FJ has, at great expense, surveyed his square farm of N x N hectares (1 <= N <= 250). Each hectare has an integer elevation (0 <= elevation <= 250) associated with it. FJ will present your program with the elevations and a set of K (1 <= K <= 100,000) queries of the form "in this B x B submatrix, what is the maximum and minimum elevation?". The integer B (1 <= B <= N) is the size of one edge of the square cornfield and is a constant for every inquiry. Help FJ find the best place to put his cornfield. Input * Line 1: Three space-separated integers: N, B, and K. * Lines 2..N+1: Each line contains N space-separated integers. Line 2 represents row 1; line 3 represents row 2, etc. The first integer on each line represents column 1; the second integer represents column 2; etc. * Lines N+2..N+K+1: Each line contains two space-separated integers representing a query. The first integer is the top row of the query; the second integer is the left column of the query. The integers are in the range 1..N-B+1. Output * Lines 1..K: A single integer per line representing the difference between the max and the min in each query.
Sample Input 5 3 1 5 1 2 6 3 1 3 5 2 7 7 2 4 6 1 9 9 8 6 5 0 6 9 3 9 1 2 Sample Output 5 Source USACO 2003 March Green 二、 题目简述: 给定一个N*N (1<=N<=250)的矩阵,给定一个数B (1<=B<=N) 和K(K<1000000)对坐标(xi,xj),求由(xi,xj)为左上点,边长为B的正方形的方框内,最大数和最小数之差. 三、 分析: 最简单的做法是强搜,每次要找到B*B中最大的数,和最小的数,最坏要N*N;而且要找K次,所以总的复杂度是O(N*N*K),最坏下要250*250*1000000=6.25*10^10,肯定TLE了. 首先考虑K,K有1000000次,但是最多的不同点只有250*250个,所以K的实际大小为250*250,这只要建一张表查就可以了。但是这次复杂度为250^4,还是不够的。我们想到,每次都进行N*N的搜索是不是太奢侈了?这是当然的。 我们可以进行一下预处理。我们定义一个maxa[251][251]的数组(为什么不叫max[][]呢?因为和STL中的max有冲突,呵呵),maxa[i][j]表示从area[i][j]到area[i+B][j]中的最大值。同样的,定义一个mina[251][251]的数组,表示从area[i][j]到area[i+B][j]中的最小值。每当一对点要计算差值时,只要进行一次maxa[][]的列扫描,一次
mina[][]的列扫描,就可以得到B*B中的最大和最小值了。 这样,问题的复杂度就降下来了,预处理时间为O(N*N*N),计算K个点的时间为O(N*K),根据前面说到的查表,可以降为O(N*N*N),所以总的时间复杂度为O(N*N*N),至此,问题圆满解次。 这里,还有一个问题,有人会问,那我预处理可不可以设一个max[251][251]的数组和min[251][251]的数组,直接把以点(i,j)为左上点,B*B大小的最大值、最小值求出来,这不是比只处理行更快麻?从处理K点上来说,每次只要O(1)时间就可以求出差值。但是,这里有个但是,预处理时间会达到O(N^4),我们又回到原来了最坏的算法上了……万事都要有个度,过了,就不好了,俗话说,物极必反。 四、 参考程序: #include<iostream> using namespace std; const int MAX=251; int small(int x, int y){return x<y?x:y;} int big(int x, int y){return x>y?x:y;} int area[MAX][MAX], maxa[MAX][MAX], mina[MAX][MAX]; int table[MAX][MAX]; int main(){ int n, b, k, x, y, i, j, q, ans1, ans2; while(scanf("%d%d%d",&n,&b,&q)!=EOF){ memset(table,-1,sizeof(table)); for(i=0;i<n;i++) for(j=0;j<n;j++) scanf("%d",&area[i][j]); for(j=0;j<n;j++){ for(i=0;i<=n-b;i++){ maxa[i][j] = area[i][j]; mina[i][j] = area[i][j]; for(k=1;k<b;k++){ maxa[i][j] = big(maxa[i][j],area[i+k][j]); mina[i][j] = small(mina[i][j], area[i+k][j]); } } }
for(i=0;i<q;i++){ scanf("%d%d",&x,&y); x--, y--; if(table[x][y]!=-1){ printf("%d/n",table[x][y]); continue; } ans1 = maxa[x][y], ans2 = mina[x][y]; for(k=1;k<b;k++){ ans1 = big(ans1, maxa[x][y+k]); ans2 = small(ans2, mina[x][y+k]); } table[x][y]=ans1-ans2; printf("%d/n",ans1 - ans2); } } } 

原创粉丝点击