有一口井,井的高度为N,每隔1个单位它的宽度有变化。现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去)。
盘子有几种命运:1、掉到井底。2、被卡住。3、落到别的盘子上方。
盘子的高度也是单位高度。给定井的宽度和每个盘子的宽度,求最终落到井内的盘子数量。
如图井和盘子信息如下:
井:5 6 4 3 6 2 3
盘子:2 3 5 2 4
最终有4个盘子落在井内。
本题由 @javaman 翻译。
Input第1行:2个数N, M中间用空格分隔,N为井的深度,M为盘子的数量(1 <= N, M <= 50000)。
第2 - N + 1行,每行1个数,对应井的宽度Wi(1 <= Wi <= 10^9)。
第N + 2 - N + M + 1行,每行1个数,对应盘子的宽度Di(1 <= Di <= 10^9)Output输出最终落到井内的盘子数量。Sample Input
7 5 5 6 4 3 6 2 3 2 3 5 2 4
Sample Output
4
刚开始想的是用两个队列来维护,但是.......后来用两个数组来存放盘子和井的宽度由于用到了两重循环结果TLE了
#include<bits/stdc++.h> #define maxn 50010 using namespace std; int main() { int n,m; int i,j; int flag; int logo; int a[maxn],b[maxn]; scanf("%d%d",&n,&m); a[0] = 0; for(i=1; i<=n; i++) { scanf("%d",&a[i]); } for(i=0; i<m; i++) { scanf("%d",&b[i]); } flag = n; for(j=0; j<m; j++) { logo = 1; for(i=0; i<flag; i++) { if(b[j] > a[i]) { flag = i; logo = 0; } } if(logo == 1) flag--; if(flag == 0) { printf("%d ",j); break; } } return 0; }
然后看了大神的博客发现时间复杂度可以简化到O(n),具体的方法就是让井的下层宽度小于或者等于上层宽度,然后从上往下以此比较
#include<bits/stdc++.h> #include<string.h> #define maxn 50010 using namespace std; int main() { int n,m; int i,j; int flag; int a[maxn],b[maxn]; scanf("%d%d",&n,&m); for(i=1; i<=n; i++) { scanf("%d",&a[i]); if(i >= 2) a[i] = min(a[i],a[i-1]); } flag = 0; for(j=0; j<m; j++) { scanf("%d",&b[j]); while(a[n] < b[j]) n--; if(n > 0) { flag++; n--; } } printf("%d ",flag); return 0; }
用栈的方法来解
#include<stdio.h> #include<string.h> #include<stack> const int M = 50005; using namespace std; int main() { int n, m; int i, j, k; int well[M], plate[M], a[M]; int ans = 0; stack<int> s; scanf("%d %d", &n, &m); for( i = 0; i < n; i++ ) { scanf("%d", &well[i]); } for( i = 0; i < m; i++ ) { scanf("%d", &plate[i]); } s.push(well[0]); for( i = 1; i < n; i++ ) { if(well[i] > well[i-1]) { well[i] = well[i-1]; } s.push(well[i]); } for( i = 0; i < m; i++ ) { while(!s.empty()) { if(s.top() >= plate[i]) { ans++; s.pop(); break; } else s.pop(); } } printf("%d", ans); return 0; }
温故而知新