【YBTOJ】防具布置

题目大意:

\(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;
}
posted @ 2020-12-25 20:32  Jayun  阅读(103)  评论(0编辑  收藏  举报