E. Frog Fights
题目连接:
http://www.codeforces.com/contest/625/problem/E
Description
stap Bender recently visited frog farm and was inspired to create his own frog game.
Number of frogs are places on a cyclic gameboard, divided into m cells. Cells are numbered from 1 to m, but the board is cyclic, so cell number 1 goes right after the cell number m in the direction of movement. i-th frog during its turn can jump for ai cells.
Frogs move in turns, game starts with a move by frog 1. On its turn i-th frog moves ai cells forward, knocking out all the frogs on its way. If there is a frog in the last cell of the path of the i-th frog, that frog is also knocked out. After this the value ai is decreased by the number of frogs that were knocked out during this turn. If ai is zero or goes negative, then i-th frog doesn't make moves anymore.
After frog number 1 finishes its turn, frog number 2 starts to move, then frog number 3 and so on. After the frog number n makes its move, frog 1 starts to move again, then frog 2 and so on this process goes forever. If some frog was already knocked out from the board, we consider that it skips all its moves.
Help Ostap to identify, what frogs will stay on the board at the end of a game?
Input
First line of the input contains two integers n and m (1 ≤ n ≤ 100000, 1 ≤ m ≤ 109, n ≤ m) — number of frogs and gameboard size, respectively.
Following n lines contains frogs descriptions — two integers pi and ai (1 ≤ pi, ai ≤ m) — the number of cell occupied by i-th frog initially and initial jump length. All pi are guaranteed to be distinct.
Output
In the first line output number of frogs on the final gameboard. In the second line output their numbers in any order.
Sample Input
3 5
2 1
5 3
4 3
Sample Output
1
3
Hint
题意
有n只青蛙,站在m大的一个环形上面
青蛙的位置是pi,每次移动ai
每只青蛙按照编号顺序移动,会撞掉他所经过的青蛙,每撞掉一只,会使得这只青蛙移动的距离减小1
然后问你一直循环下去,还剩下哪些青蛙
题解:
模拟
但是别按照编号的顺序去模拟,我们按照相撞的时间先后顺序去模拟就好了
首先我们可以得到一个信息,这只青蛙如果会和别的青蛙相撞,那么最先相撞的,肯定是他的下一只青蛙。
然后我们把相撞的时间记录下来(究竟是第几个回合,才会撞到那只青蛙
然后我们用一个Set或者优先队列,不断模拟这个过程就好了
每次抽出相撞时间最短的青蛙来,然后撞掉。
最后剩下的青蛙都不相撞为止。
因为每次更新的复杂度是logn,每次更新必定会减小一只青蛙,所以复杂度是nlogn的
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
const int inf = 1e9+7;
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)/2;
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()
{
scanf("%d%d",&n,&m);
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(auto s:S)
printf("%d ",s.second+1);
printf("\n");
}