题意:机器人比赛跑步,知道了初始位置,和加速度,求有多少机器人能成为领头羊(在某一刻跑到第一名,不能并列)
思路:因为知道了加速度,所以很容易知道,当加速度最快的成为了领头羊,其他机器人就没机会了,并且,当一个机器人在初始位置和加速度都比前面的机器人小的话,也不可能。根据这两个特性,我们就可以通过将机器人的初始位子从大到小进行比较,如果一个机器人的加速度比前面所有机器人的加速度都要大,那这个机器人能当,不然不可能
点击查看代码
int sgn(double x) // 因为是double,需要用到精度
{if (fabs(x) < ep)return 0;if (x > 0)return 1;return -1;
}struct point
{ll a, p;
} a[N];
int cmp(point a, point b) // 按照位置进行排序
{if (a.p == b.p)return a.a > b.a;return a.p > b.p;
}
vector<int> v;
int n;
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin >> t;while (t--){cin >> n;a[n + 1].a = a[n + 1].p = 0;for (int i = 1; i <= n; i++)cin >> a[i].p >> a[i].a;sort(a + 1, a + 1 + n, cmp);// 加速度最大的那个人肯定是最后的赢家ll ma = a[1].a;stack<PII> s; // s存储的是从能超过最后一个机器人的下标,时间从小到大s.push({1, 1});for (int i = 2; i <= n; i++){if (a[i].a <= ma)continue;// 如果加速度小于且本来位置比较靠后的话是不可能超过前面那个人的ma = a[i].a;int y = 1; // y储存的是在i之前的超过最后一个机器人的最快机器人的下标while (!s.empty()){PII from = s.top();int o = from.first;int r = from.second;double t2 = sqrt(2.0 * (a[i].p - a[o].p) / (a[o].a - a[i].a)); // 超过的时间就是距离除以速度差double t1 = 0;if (o != r)t1 = sqrt(2.0 * (a[o].p - a[r].p) / (a[r].a - a[o].a));if (sgn(t2 - t1) <= 0)// 利用精度进行比较{y = r;s.pop();// 如果机器人i的速度比机器人r的速度快,说明在num1超过num2之前i就超过了num1,更新最快机器人的位置}else{y = o;break;}}s.push({i, y});// 因为这个人的加速度最大,所以他在这前i个人中肯定是最后的赢家}int ans = s.size();while (!s.empty()){PII from = s.top();s.pop();int y = from.first;if (a[y].a == a[y + 1].a && a[y].p == a[y + 1].p) // 判断是否有一起超过的情况ans--;}cout << ans << "\n";}
}