第1行:1个数N,表示鱼的数量(1 <= N <= 100000)。 第2 - N + 1行:每行两个数A[i], B[i],中间用空格分隔,分别表示鱼的大小及游动的方向(1 <= A[i] <= 10^9,B[i] = 0 或 1,0表示向左,1表示向右)。
输出1个数,表示最终剩下的鱼的数量。
5 4 0 3 1 2 0 1 0 5 0
2
一开始看这题的时候, 看上面写着模拟, 以为是手动模拟打秒, 然后计算碰撞存活的鱼数. 然后发现题目说了是x轴, 并且没有说明长度, 所以可视为无限长, 游动的速度一样说明同向的鱼永远不会相遇, 方向相对的, 肯定会相遇, 发生大于吃小鱼. 所以只要简单地模拟, 然后检查相邻的鱼中的碰撞情况. 上代码, 再解释.
#include#include #include using namespace std; const int MAX = 100000; int sameHeadFish[MAX + 3]; int main() { int n, cnt = 0, head, sze, preHead, preSze, sameHead = 0; //freopen("tmp.in", "r", stdin); scanf("%d", &n); scanf("%d%d", &preSze, &preHead); for(int i = 1; i < n; i++) { scanf("%d%d", &sze, &head); if(head == preHead) sameHeadFish[sameHead++] = sze; else if(preHead == 0){ cnt++; cnt += sameHead; sameHead = 0; preSze = sze; preHead = head; }else{ int j; for(j = sameHead-1; j >= 0; j--) { if(sameHeadFish[j] > sze)break; } if(j >= 0) { sameHead = j + 1; }else if(sze > preSze){ preSze = sze; preHead = head; sameHead = 0; }else{ sameHead = 0; } } } cnt++; cnt += sameHead; printf("%d", cnt); return 0; }
第一种情况, 相邻的鱼方向相同, 把右边的鱼加入队列.
第二种情况, 相邻的鱼方向不同且相反, 也就是左边的鱼向左, 右边的鱼向右, 这种情况直接把队列里的鱼数加入存活的鱼数再加一. 简单解释下为什么可以直接把队列里的鱼还有左边的鱼视为存活, 因为接下来的鱼, 不管是向左还是向右, 都不会吃掉队列里的鱼(这些鱼向左).
第三种情况, 相邻的鱼方向不同且相对, 也就是左边的鱼向右, 右边的鱼向左, 发生碰撞. 这时, 右边的鱼会吃掉队列中从右向左比它小的鱼.
当然了, 我这算法并不算好. 281ms才跑出来
附上神犇的代码(31ms)
#include"stdio.h" #include"stdlib.h" #include"string.h" #include"algorithm" #include"iostream" #include"math.h" #include"ctype.h" #include"stack" using namespace std; int main() { stack s; int n; scanf("%d",&n); int ans=n; while(n--) { int x,y; scanf("%d%d",&x,&y); if(y==1) s.push(x); else { while(!s.empty()) { if(x>s.top()) {s.pop();ans--;} else {ans--; break;} } } } printf("%d\n",ans); return 0; }