>Link
ybtoj防具布置
>解题思路
设 s i s_{i} si为前 i i i个位置的防具总数, s i s_i si我们可以运用数学知识 O ( n ) O(n) O(n)求出来
因为“整个防线上有且仅有一个位置有破绽或根本没有破绽”,所以当
s
i
s_i
si为偶数时,前
i
i
i个位置上一定没有破绽,为奇数则说明破绽一定在前
i
i
i个位置中
考虑二分防线的位置,找到第一个为奇数的
s
i
s_i
si,
如果
s
m
i
d
s_{mid}
smid为奇数,则答案在前
m
i
d
mid
mid之中
如果
s
m
i
d
s_{mid}
smid为偶数,则答案在
m
i
d
+
1
mid+1
mid+1之后
时间复杂度大概为 O ( 31 N ) O(31N) O(31N)
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
#define LL long long
using namespace std;
int T, n;
LL s[N], e[N], d[N], l, r, mid, ans;
LL asksum (LL x)
{
LL sum = 0;
for (int i = 1; i <= n; i++)
if (s[i] <= x) sum += (min (x, e[i]) - s[i]) / d[i] + 1;
return sum;
}
void work ()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
scanf ("%lld%lld%lld", &s[i], &e[i], &d[i]);
if (asksum ((LL)2147483647) % 2 == 0) {printf ("There's no weakness.\n"); return;}
l = ans = 1, r = (LL)2147483647;
while (l < r)
{
mid = (l + r) / 2;
if (asksum (mid) % 2 == 1) r = mid;
else l = mid + 1;
}
printf ("%lld %lld\n", r, asksum (r) - asksum (r - 1));
}
int main()
{
scanf ("%d", &T);
while (T--) work ();
return 0;
}