题目描述
在秦腾进入北京大学学习的第一个学期,就不幸遇到了前所未有的教学评估。
在教学评估期间,同学们被要求八点起床,十一点回宿舍睡觉,不 准旷课,上课不准迟到,上课不准睡觉……甚至连著名的北大三角地也在教学评估期间被以影响校容的理由被拆除。这些“变态”规定令习惯了自由自在随性生活学习的北大同学叫苦不迭。
这一天又到了星期五,一大早就是秦腾最不喜欢的高等代数课。可是因为是教学评估时期,不能迟到,于是他在八点五分的 时候挣扎着爬出了宿舍,希望能赶快混进在八点钟已经上课了的教室。
可是,刚一出宿舍楼门他就傻眼了: 从宿舍到教学楼的路上已经站满了教学评估团的成员。他们的目的就是抓住像他这样迟到的学生,扣除学校的分数。
秦腾当然不能让评估团得逞。他经过观察发现,整个评估团分成了N个小组,每个小组的成员都分布在从宿舍楼到教学楼的路上的某一段,并且同一小组的成员间的距离是相等的。于是,我们可以用三个整数S, E, D来描述评估团的小组: 既该小组的成员在从宿舍到教学楼的路上的:S, S + D, S + 2D, …, S + KD (K ∈ Z, S + KD ≤ E, S + (K + 1)D > E)位置。
观 察到了教学评估团的这一特点,又经过了认真的思考,秦腾想出了对策: 如果在路上的某一位置有奇数个教学评估团成员,他就可以运用调虎离山,声东击西,隔山打牛,暗度陈仓……等方法,以这一地点为突破口到达教学楼。
但是由于 教学评估团的成员的十分狡猾,成员位置安排的设计极其精妙,导致在整条路上几乎没有这样的位置出现。即使由于安排不慎重出现了这样的位置,最多也仅有一个。
现在秦腾观察出了所有小组的安排,但是由于整个教学评估团的人数太多,他实在看不出这样的位置是否存在。
现在,你的任务是写一个程序,帮助他做出判断。
输入输出格式
输入格式:
输入文件的第一行为一个整数T。
接下来输入T组相互独立的测试数据。
每组测试数据的第一行包含一个整数,代表N接下来的N行,每行三个整数Si, Ei, Di, 代表第i个小组对应的三个参数。
输出格式:
对于每个测试数据,如果题目中所求的位置不存在,既任意位置都有偶数个教学评估团的成员存在,在输出文件的中打印一行:Poor QIN Teng:(
(不包含引号)否则打印两个整数Posi, Count,代表在唯一的位置Posi,有Count个教学评估团的成员。
根据题意,Count应为奇数。
输入输出样例
说明
教学评估团的总人数不大于10^8
Si ≤ Ei
1 ≤ T ≤ 5
N ≤ 200000
0 ≤ Si, Ei, Di ≤ 2^31 – 1
输入文件的大小不大于2048KB
这道题我第一眼一看到线性的就往线段树上去想了,但是其实是一道二分。
这道题如果直接暴力跑的话,数组开不下,只能得到20分。
这道题的突破口其实是在最多只有一个点是奇数的。
那么就可以用前缀和来找到第一个为奇数的点的位置。
在前缀和寻找的时候可以二分寻找的点。
二分的点上再O(n)跑一遍,求一下前缀和的奇偶性。
如果是奇数就说明答案在这个点之前(包括这个点),反之则在这个点的后面。
代码如下:
1 #include<cstdio>
2 #include<cmath>
3 #include<algorithm>
4 using namespace std;
5 typedef long long ll;
6 const ll maxn = 200010;
7 ll read() {
8 ll a = 0,b = 1;
9 char c = getchar();
10 while(c < '0' or c > '9') {
11 if(c == '-') b = -1;
12 c = getchar();
13 }
14 while(c >= '0' and c <= '9') {
15 a = a * 10 + c - '0';
16 c = getchar();
17 }
18 return a * b;
19 }
20 ll s[maxn],d[maxn],e[maxn],n;
21 ll getsum(ll limit) {
22 ll ans = 0;
23 for(int i=1; i<=n; i++) {
24 if(s[i] > limit) continue;
25 ll r = min(e[i], limit);
26 ans+=(r - s[i])/d[i] + 1;
27 }
28 return ans;
29 }
30 int main() {
31 ll T;
32 T = read();
33 for(int i=1; i<=T; i++) {
34 n = read();
35 ll limit = 0;
36 for(int i=1; i<=n; i++) {
37 s[i] = read();
38 e[i] = read();
39 d[i] = read();
40 limit = max(limit, e[i]);
41 }
42 ll sum = getsum(limit);
43 if(sum % 2 == 0) {
44 printf("Poor QIN Teng:(
");
45 continue;
46 }
47 ll l = 0,r = limit, ans = 0;
48 while(l <= r) {
49 ll mid = (l+r) >> 1;
50 if(getsum(mid)&1) {
51 ans = mid;
52 r = mid-1;
53 } else
54 l = mid+1;
55 }
56 ll cnt = 0;
57 for(int i=1; i<=n; i++) {
58 if(s[i] > ans) continue;
59 if(e[i] < ans) continue;
60 if((ans - s[i]) % d[i] == 0 ) cnt++;
61 }
62 printf("%lld %lld
",ans,cnt);
63 }
64 return 0;
65 }