【YBTOJ】防具佈置
阿新 • • 發佈:2020-12-25
題目大意:
有 \(n\) 組防具。第 \(i\) 個防具會標記在區間 \(\[S_i,E_i\]\) 中模 \(D_i\) 的值是 \(S_i\bmod D_i\) 的位置。求哪個位置被標記了奇數次。
正文:
我們可以考慮二分。那麼找一下題目中隱藏的單調性。
可以發現,我們可以用一段區間的標記總值作為 key,比如當前二分到 \([l,r]\),我們可以先判斷 \([l,mid]\) 的是否為奇數。如果是,則縮短範圍到 \([l,mid]\);若不是,說明 \([mid+1,r]\) 必有一點是奇數,則縮小範圍至 \([mid+1,r]\)。
程式碼:
const int N = 2e5 + 10; int t, n; ll a[N][3]; ll calc(ll r) { ll ans = 0; for (int i = 1; i <= n; i++) { if (a[i][0] > r) continue; ans += (min(r, a[i][1]) - a[i][0]) / a[i][2] + 1; } return ans; } bool check (ll l, ll r) { return (calc(r) - calc(l - 1)) % 2; } int main() { ll l, r; scanf ("%d", &t); for (; t--; ) { scanf ("%d", &n); r = 0ll, l = 1ll << 40; for (int i = 1; i <= n; i++) { scanf ("%lld%lld%lld", &a[i][0], &a[i][1], &a[i][2]); l = min (l, a[i][0]); r = max (r, a[i][1]); } if (!check(l, r)) {puts("There's no weakness."); continue;} while (l <= r) { ll mid = l + r >> 1ll; if (check(l, mid)) r = mid - 1; else l = mid + 1; } printf ("%lld %lld\n", l, calc(l) - calc(l - 1)); } return 0; }