CF625E Frog Fights 题解
用链表维护青蛙,任意两只青蛙之间没有别的青蛙
用set把青蛙按照"能干掉下一只青蛙的时间"从小到大排序
每次取出最小值更新即可
这里有一个小trick:关于为什么要将\(p_i\)加上\(calc(i,nxt_i)\)呢
对于这个要跳的青蛙(叫做A)之前的青蛙,A跳完之后步数-1,青蛙A跳之前前面青蛙先跳(相当于追A)的时候,以A的步数为\(a_i\)算的,后面A撞飞青蛙完之后以\(a_{i}-1\)来追的,所以要补上
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
#define int long long
set<pair<int,int> > st;
const int INF = 1<<30;
const int N = 100005;
int p[N],n,m;
int nxt[N],pre[N];
int a[N],x[N];
inline int read() {
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
bool cmp(int x,int y) {
return p[x] < p[y];
}
int calc(int x,int y) {
if(x == y) return INF;
int d = (p[y]-p[x]+m) % m;
//默认x先跳,当y先跳时先加上
if(x > y) d = (d + a[y]) % m;
//特判
if(d <= a[x]) return 1;
//x比y跑的慢,永远追不上
if(a[x] <= a[y]) return INF;
int dis = a[x]-a[y];
//如果追上了,就不用再跳a[y]
return (d-a[y]-1)/dis+1;
}
signed main () {
n = read();m = read();
for(int i = 1;i <= n;i++) {
p[i] = read();
a[i] = read();
x[i] = i;
}
sort(x+1,x+n+1,cmp);
for(int i = 1;i <= n;i++) {
if(i < n) nxt[x[i]] = x[i+1];
else nxt[x[i]] = x[1];
pre[nxt[x[i]]] = x[i];
}
for(int i = 1;i <= n;i++) {
st.insert(make_pair(calc(i,nxt[i]),i));
}
while(!st.empty()) {
set<pair<int,int> >::iterator it = st.begin();
if((*it).first == INF) break;
int i = (*it).second;
st.erase(it);
st.erase(make_pair(calc(nxt[i],nxt[nxt[i]]),nxt[i]));
st.erase(make_pair(calc(pre[i],i),pre[i]));
p[i] += calc(i,nxt[i]);
--a[i];
nxt[i] = nxt[nxt[i]];
pre[nxt[i]] = i;
st.insert(make_pair(calc(pre[i],i),pre[i]));
st.insert(make_pair(calc(i,nxt[i]),i));
}
printf("%d\n",st.size());
for(set<pair<int,int> >::iterator it = st.begin();it != st.end();it++) printf("%lld ",(*it).second);
}

浙公网安备 33010602011771号