1. 程式人生 > 其它 >防具佈置【二分】

防具佈置【二分】

技術標籤:二分

>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; }