https://www.acwing.com/problem/content/122/
题意:给2e6个区间,每个区间三个数Si,Ei,Di,表示在[Si,Ei]范围内,距离Si每隔Di都有一个装备,范围是[0,INT_MAX]。
题目保证有奇数个装备的点至多一个,要找这个点。
题解说,要找这种只有一个的奇数点,想到前缀和是非常自然的(现在学会了之后就非常自然)。
那么二分这个位置求前缀和就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, S[200005], E[200005], D[200005];
int query(int x, int i) {
//询问x位置及其之前有多少个防具i
if(x < S[i])
return 0;
if(D[i] == 0)
return 1;
if(x > E[i])
x = E[i];
return (x - S[i]) / D[i] + 1;
}
int sum(int x) {
//询问x位置及其之前的防具前缀和是不是奇数
int s = 0;
for(int i = 1; i <= n; ++i) {
s += query(x, i);
}
//printf("x=%d sum=%d
", x, s);
return s;
}
int check(int x) {
return (sum(x) & 1);
}
int bs() {
int l = 0, r = INT_MAX;
while(1) {
int m = l + ((r - l) >> 1);
if(l == m) {
if(check(l))
return l;
else if(check(r))
return r;
else
return -1;
}
if(check(m))
r = m;
else
l = m + 1;
}
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int T;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d%d%d", &S[i], &E[i], &D[i]);
}
int ans = bs();
if(ans == -1)
puts("There's no weakness.");
else
printf("%d %d
", ans, sum(ans) - sum(ans - 1));
}
}