Codeforces Round #342 (Div. 2) E. Frog Fights set 模拟(等效处理,难)

本文介绍了一种模拟青蛙在环形路径上移动并相互碰撞的算法。通过优先队列记录每只青蛙相遇的时间,并据此更新青蛙的位置及速度,最终确定哪些青蛙不会发生碰撞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

有n只青蛙,站在m大的一个环形上面

青蛙的位置是pi,每次移动ai

每只青蛙按照编号顺序移动,会撞掉他所经过的青蛙,每撞掉一只,会使得这只青蛙移动的距离减小1

然后问你一直循环下去,还剩下哪些青蛙

题解:

模拟

但是别按照编号的顺序去模拟,我们按照相撞的时间先后顺序去模拟就好了

首先我们可以得到一个信息,这只青蛙如果会和别的青蛙相撞,那么最先相撞的,肯定是他的下一只青蛙。

然后我们把相撞的时间记录下来(究竟是第几个回合,才会撞到那只青蛙

然后我们用一个Set或者优先队列,不断模拟这个过程就好了

每次抽出相撞时间最短的青蛙来,然后撞掉。

最后剩下的青蛙都不相撞为止。

因为每次更新的复杂度是logn,每次更新必定会减小一只青蛙,所以复杂度是nlogn的

[cpp]  view plain  copy
  1. #include <set>  
  2. #include <map>  
  3. #include <stack>  
  4. #include <queue>  
  5. #include <deque>  
  6. #include <cmath>  
  7. #include <vector>  
  8. #include <string>  
  9. #include <cstdio>  
  10. #include <cstdlib>  
  11. #include <cstring>  
  12. #include <iostream>  
  13. #include <algorithm>  
  14. using namespace std;  
  15. #define L(i) i<<1  
  16. #define R(i) i<<1|1  
  17. #define INF  0x3f3f3f3f  
  18. #define pi acos(-1.0)  
  19. #define eps 1e-9  
  20. #define maxn 1000100  
  21. #define MOD 1000000007  
  22. #include<bits/stdc++.h>  
  23. int n,m;  
  24. int p[maxn],a[maxn];  
  25. int nxt[maxn],pre[maxn];  
  26. set<pair<int,int> > S;  
  27. pair<int,int> c[maxn];  
  28.   
  29. int time(int x,int y)  
  30. {  
  31.     if(x == y)  
  32.         return INF;  
  33.     long long p1 = p[x],p2 = p[y];  
  34.     if(x > y)  
  35.         p2 = (p2 + a[y]) % m;  
  36.     if(p2 < p1)  
  37.         p2 += m;  
  38.     if(p2 - p1 <= a[x])  
  39.         return 1;  
  40.     if(a[y] >= a[x])  
  41.         return INF;  
  42.     int l = 1,r = INF,ans = INF;  
  43.     while(l <= r)  
  44.     {  
  45.         int mid = (l + r) >> 1;  
  46.         if(p1 + 1ll*a[x]*mid >= p2 + 1ll*a[y]*(mid-1))  
  47.             ans = mid,r = mid - 1;  
  48.         else  
  49.             l = mid + 1;  
  50.     }  
  51.     return ans;  
  52. }  
  53. int main()  
  54. {  
  55.     //freopen("in.txt","r",stdin);  
  56.     //freopen("out.txt","w",stdout);  
  57.     int t,C = 1;  
  58.     //scanf("%d",&t);  
  59.     while(scanf("%d%d",&n,&m) != EOF)  
  60.     {  
  61.         for(int i = 0; i < n; i++)  
  62.         {  
  63.             scanf("%d%d",&p[i],&a[i]);  
  64.             p[i]--;  
  65.             c[i].first = p[i];  
  66.             c[i].second = i;  
  67.         }  
  68.         sort(c,c+n);  
  69.         for(int i = 0; i < n; i++)  
  70.         {  
  71.             nxt[c[i].second] = c[(i+1)%n].second;  
  72.             pre[c[i].second] = c[(i-1+n)%n].second;  
  73.         }  
  74.         for(int i = 0; i < n; i++)  
  75.             S.insert(make_pair(time(i,nxt[i]),i));  
  76.         while(!S.empty())  
  77.         {  
  78.             pair<int,int> now = *S.begin();  
  79.             if(now.first == INF)  
  80.                 break;  
  81.             S.erase(now);  
  82.             int x = now.second;  
  83.             S.erase(make_pair(time(nxt[x],nxt[nxt[x]]),nxt[x]));  
  84.             S.erase(make_pair(time(pre[x],x),pre[x]));  
  85.             p[x] += now.first;    //  把连续的碰撞,离散等效了
  86.             a[x]--;               //  相对距离减次数,因为速度依次减,前面走的相当于减少了相对距离
  87.             nxt[x] = nxt[nxt[x]];  
  88.             pre[nxt[x]] = x;  
  89.             S.insert(make_pair(time(pre[x],x),pre[x]));  
  90.             S.insert(make_pair(time(x,nxt[x]),x));  
  91.         }  
  92.         printf("%d\n",S.size());  
  93.         for(set<pair<int,int> >::iterator it = S.begin(); it != S.end(); it++)  
  94.             printf("%d ",(*it).second+1);  
  95.         printf("\n");  
  96.     }  
  97.     return 0;  
  98. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值