Codeforces Round #342 (Div. 2) E. Frog Fights set 模拟★ ★

题意

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

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

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

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

题解:

模拟

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

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

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

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

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

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

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

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF  0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-9
#define maxn 1000100
#define MOD 1000000007
#include<bits/stdc++.h>
int n,m;
int p[maxn],a[maxn];
int nxt[maxn],pre[maxn];
set<pair<int,int> > S;
pair<int,int> c[maxn];

int time(int x,int y)
{
    if(x == y)
        return INF;
    long long p1 = p[x],p2 = p[y];
    if(x > y)
        p2 = (p2 + a[y]) % m;
    if(p2 < p1)
        p2 += m;
    if(p2 - p1 <= a[x])
        return 1;
    if(a[y] >= a[x])
        return INF;
    int l = 1,r = INF,ans = INF;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(p1 + 1ll*a[x]*mid >= p2 + 1ll*a[y]*(mid-1))
            ans = mid,r = mid - 1;
        else
            l = mid + 1;
    }
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,C = 1;
    //scanf("%d",&t);
    while(scanf("%d%d",&n,&m) != EOF)
    {
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d",&p[i],&a[i]);
            p[i]--;
            c[i].first = p[i];
            c[i].second = i;
        }
        sort(c,c+n);
        for(int i = 0; i < n; i++)
        {
            nxt[c[i].second] = c[(i+1)%n].second;
            pre[c[i].second] = c[(i-1+n)%n].second;
        }
        for(int i = 0; i < n; i++)
            S.insert(make_pair(time(i,nxt[i]),i));
        while(!S.empty())
        {
            pair<int,int> now = *S.begin();
            if(now.first == INF)
                break;
            S.erase(now);
            int x = now.second;
            S.erase(make_pair(time(nxt[x],nxt[nxt[x]]),nxt[x]));
            S.erase(make_pair(time(pre[x],x),pre[x]));
            p[x] += now.first,a[x]--;
            nxt[x] = nxt[nxt[x]];
            pre[nxt[x]] = x;
            S.insert(make_pair(time(pre[x],x),pre[x]));
            S.insert(make_pair(time(x,nxt[x]),x));
        }
        printf("%d\n",S.size());
        for(set<pair<int,int> >::iterator it = S.begin(); it != S.end(); it++)
            printf("%d ",(*it).second+1);
        printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值