CH0805 防线 二分

题目链接

http://noi-test.zzstep.com/contest/0x08%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E7%BB%83%E4%B9%A0/0805%20%E9%98%B2%E7%BA%BF%EF%BC%88%E7%A7%A6%E8%85%BE%E4%B8%8E%E6%95%99%E5%AD%A6%E8%AF%84%E4%BC%B0%EF%BC%89

分析

二分防具个数是奇数的位置,统计该位置即之前共有多少防具,看总和是否为奇数。

AC代码

#include 
#include 

using namespace std;

inline int read() {
	int num = 0;
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9')
		num = num * 10 + c - '0', c = getchar();
	return num;
}

const int maxn = 2e5 + 5;

struct Raid {
	int s, e, d;

	bool operator < (const Raid& rhs) const {
		return s < rhs.s;
	}
} raid[maxn];

int n;

inline int judge(int x) {
	int sum = 0;
	for (int i = 1; raid[i].s <= x && i <= n; ++i)
		sum += (min(x, raid[i].e) - raid[i].s) / raid[i].d + 1;
	return sum & 1;
}

int main() {
	int t = read();
	while (t--) {
		n = read();
		for (int i = 1; i <= n; ++i)
			raid[i].s = read(), raid[i].e = read(), raid[i].d = read();
		sort(raid + 1, raid + n + 1);
		int l = 1, r = (1ll << 31) - 1;
		while (l < r) {
			int mid = (1ll * l + r) >> 1;
			if (judge(mid)) r = mid;
			else l = mid + 1;
		}
		if (!judge(l)) printf("There's no weakness.\n");
		else {
			int cnt = 0;
			for (int i = 1; i <= n; ++i) {
				if (raid[i].s > l) break;
				if (raid[i].e >= l && (l - raid[i].s) % raid[i].d == 0) ++cnt;
			}
			printf("%d %d\n", l, cnt);
		}
	}
	return 0;
}

你可能感兴趣的:(《算法竞赛进阶指南》,题解,二分答案)