秦腾与教学评估
题目链接:luogu P4403
题目大意
有 n 个小组,每个小组会从 Si 开始,每隔 Di 有一个人,一直到 Ei。
然后现在已知至多有一个位置有奇数个人,要你找到这个位置,或者判断出没有这个位置。
思路
发现只有一个位置有奇数,考虑从这里下手。
然后奇数有这么一个性质,就是它无论加多少个偶数,得到的都是奇数。
而且你发现你这一道题,你可以用
O
(
n
)
O(n)
O(n) 的时间内求出任意一个范围有多少个人。
那你考虑二分,你把你当前的区间分成两个部分,那如果两个区间的出来的都是偶数,那就说明这个区间里面没有。那一个区间的的出来的是奇数,答案就在哪一个区间里面。
(因为只有一个奇数)
然后二分一下每次判断就可以了。
代码
#include<cstdio>
#include<iostream>
#define mo 1000003
#define ll long long
using namespace std;
struct node {
int s, e, d;
}a[200001];
int T, n, re;
ll l, r, ans;
char c;
int read() {
re = 0; c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
re = (re << 3) + (re << 1) + c - '0';
c = getchar();
}
return re;
}
int count(int R) {
int re = 0;
for (int i = 1; i <= n; i++) {//每个组算一下多少个
int r = min(R, a[i].e);
if (a[i].s > r) continue;
re += 1 + (r - a[i].s) / a[i].d;
}
return re;
}
int main() {
// printf("%.3lf", (sizeof(e) + sizeof(le)) / 1024.0);
T = read();
while (T--) {
n = read();
for (int i = 1; i <= n; i++) {
scanf("%d %d %d", &a[i].s, &a[i].e, &a[i].d);
}
l = 1; r = 2147483647; ans = -1;//二分
while (l <= r) {
ll mid = (l + r) >> 1;
if ((count(mid) - count(l - 1)) & 1) ans = mid, r = mid - 1;
else l = mid + 1;
}
if (ans == -1) printf("Poor QIN Teng:(\n");
else {
printf("%d %d\n", ans, count(ans) - count(ans - 1));
}
}
return 0;
}