防具佈置【二分】
阿新 • • 發佈:2021-01-10
技術標籤:二分
>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;
}