【CodeForces】CodeForces Round #517 (Div. 1 + Div. 2) 题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/83278746

【比赛链接】

【题解链接】

**【Div.2 A】**Golden Plate

【思路要点】

  • 直接循环计算答案即可。
  • 时间复杂度 O ( K ) O(K)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int main() {
	int n, m, k;
	read(n), read(m), read(k);
	int ans = 0;
	for (int i = 1; i <= k; i++) {
		int x = n - 4 * (i - 1);
		int y = m - 4 * (i - 1);
		ans += x * 2 + y * 2 - 4;
	}
	writeln(ans);
	return 0;
}

**【Div.2 B】**Curiosity Has No Limits

【思路要点】

  • 首先,每一位的方案是相互独立的,我们可以分开考虑。
  • 当确定 x , x &amp; y , x y x,x\&amp;y,x|y 时,合法的 y y 至多只有 1 1 个。
  • 因此枚举开头位置,构造出序列,再检验合法性即可。
  • 时间复杂度 O ( N ) O(N)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, a[MAXN], b[MAXN], x[MAXN];
int func(int a, int b, int x) {
	if (a == b) return a;
	else if (a == 0) return 0;
	else return 1 - x;
}
bool tryans(int f) {
	x[1] = f;
	for (int i = 1; i <= n - 1; i++)
		x[i + 1] = func(a[i] / 2, b[i] / 2, x[i] / 2) * 2 + func(a[i] % 2, b[i] % 2, x[i] % 2);
	for (int i = 1; i <= n - 1; i++) {
		if ((x[i] | x[i + 1]) != a[i]) return false;
		if ((x[i] & x[i + 1]) != b[i]) return false;
	}
	return true;
}
void answer() {
	printf("YES\n");
	for (int i = 1; i <= n; i++)
		printf("%d ", x[i]);
	exit(0);
}
int main() {
	read(n);
	for (int i = 1; i <= n - 1; i++)
		read(a[i]);
	for (int i = 1; i <= n - 1; i++)
		read(b[i]);
	if (tryans(0)) answer();
	if (tryans(1)) answer();
	if (tryans(2)) answer();
	if (tryans(3)) answer();
	printf("NO\n");
	return 0;
}

**【Div.2 C/Div.1 A】**Cram Time

【思路要点】

  • x x 表示最大的使得 x ( x + 1 ) 2 a + b \frac{x(x+1)}{2}≤a+b 的整数,答案显然有上界为 x x
  • 若我们保证第一天用完刚好 a a 小时或完成所有 x x 个任务,那么答案将一定会取到上界。只需要从大到小考虑每个任务,优先将其安排在第一天即可。
  • 时间复杂度 O ( a + b ) O(\sqrt{a+b})

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
vector <int> a, b;
int main() {
	int n, m; read(n), read(m);
	int sum = n + m, tot = 0;
	while (sum >= tot + 1) {
		tot++;
		sum -= tot;
	}
	for (int i = tot; i >= 1; i--)
		if (n >= i) {
			n -= i;
			a.push_back(i);
		} else b.push_back(i);
	writeln(a.size());
	for (auto x : a)
		printf("%d ", x);
	printf("\n");
	writeln(b.size());
	for (auto x : b)
		printf("%d ", x);
	printf("\n");
	return 0;
}

**【Div.2 D/Div.1 B】**Minimum path

【思路要点】

  • 分层 D P DP ,令点 ( i , j ) (i,j) 为第 i + j 1 i+j-1 层的点。
  • 首先确定答案的第 i i a n s i ans_i ,再计算得出能够取到最优答案的第 i i 层的结尾位置以及这些位置最多能够剩余的修改次数,层层递进即可。
  • 时间复杂度 O ( N 2 ) O(N^2)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e3 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, k, dp[MAXN][MAXN];
char s[MAXN][MAXN], ans[MAXN * 2];
int main() {
	read(n), read(k);
	for (int i = 1; i <= n; i++)
		scanf("\n%s", s[i] + 1);
	memset(dp, -1, sizeof(dp));
	if (s[1][1] == 'a' || k >= 1) {
		ans[1] = 'a';
		dp[1][1] = k - (s[1][1] != 'a');
	} else {
		ans[1] = s[1][1];
		dp[1][1] = 0;
	}
	for (int i = 2, now = 0, dest = 1; i <= 2 * n - 1; i++, swap(now, dest)) {
		char opt = 'z';
		for (int x = 1; x <= n; x++) {
			int y = i - x;
			if (y < 0 || y > n || dp[x][y] == -1) continue;
			if (dp[x][y]) opt = 'a';
			if (x + 1 <= n) chkmin(opt, s[x + 1][y]);

			if (y + 1 <= n) chkmin(opt, s[x][y + 1]);
		}
		ans[i] = opt;
		for (int x = 1; x <= n; x++) {
			int y = i - x;
			if (y < 0 || y > n || dp[x][y] == -1) continue;
			if (dp[x][y]) {
				if (x + 1 <= n) chkmax(dp[x + 1][y], dp[x][y] - (s[x + 1][y] != 'a'));
				if (y + 1 <= n) chkmax(dp[x][y + 1], dp[x][y] - (s[x][y + 1] != 'a'));
			} else {
				if (x + 1 <= n && s[x + 1][y] == opt) chkmax(dp[x + 1][y], dp[x][y]);
				if (y + 1 <= n && s[x][y + 1] == opt) chkmax(dp[x][y + 1], dp[x][y]);
			}
		}
	}
	printf("%s\n", ans + 1);
	return 0;
}

**【Div.2 E/Div.1 C】**Triple Flips

【思路要点】

  • 写一个暴力,事实表明当 N 8 N≥8 ,问题将始终有解,并且 N = 12 N=12 的所有情况均存在一个 5 5 步内的解。
  • 接下来我们的思路是通过大约 N 3 \frac{N}{3} 次操作将序列包含 1 1 的长度减小至 12 12 ,并通过暴力解决剩余的问题。
  • 由于能够进行的操作数只有大约 N 3 \frac{N}{3} 次,我们需要保证在 1 1 步内将序列包含 1 1 的长度减小 3 3 ,或是在 2 2 步内将序列包含 1 1 的长度减小 6 6
  • 以下是笔者的做法:
    1 1 、判断当前区间开头 3 3 个元素是否均为 1 1 ,若是,用一次操作处理之,并删去区间开头 3 3 个元素;区间结尾 3 3 个元素同理。
    2 2 、现在我们可以认为区间开头、结尾 3 3 个元素均至多有 2 2 1 1 。若区间开头 3 3 个元素只有 1 1 1 1 ,用一次操作处理之,并删去区间开头 3 3 个元素,区间结尾 3 3 个元素同理。
    3 3 、现在我们可以认为区间开头、结尾 3 3 个元素均恰好有 2 2 1 1 。若区间开头 3 3 个元素形如 1 , 0 , 1 1,0,1 ,用一次操作处理之,并删去区间开头 3 3 个元素,区间结尾 3 3 个元素同理。
    4 4 、剩余的唯一情况是区间开头 3 3 个元素形如 1 , 1 , 0 1,1,0 ,区间结尾 3 3 个元素形如 0 , 1 , 1 0,1,1 。可用两次操作处理之,并删去区间开头、结尾的 3 3 个元素。
  • 如此迭代删除,直至区间长度降至恰好 12 12
  • 时间复杂度 O ( N + 2 12 1 2 2 ) O(N+2^{12}*12^2) ,使用操作次数不超过 N 3 + 5 \lfloor\frac{N}{3}\rfloor+5

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
vector <int> x, y, z;
namespace force {
	const int MAXN = 13;
	unordered_map <bitset <MAXN>, bitset <MAXN> > from;
	bitset <MAXN> q[1 << MAXN], dest;
	void work(int *a, int n, int delta) {
		dest.reset();
		for (int i = 1; i <= n; i++)
			dest[i] = a[i];
		if (dest == 0) return;
		int l = 0, r = 0;
		q[0] = 0, from[0] = 0;
		while (l <= r) {
			bitset <MAXN> now = q[l++];
			for (int i = 1; i <= n; i++)
			for (int j = i + 2; j <= n; j += 2) {
				int k = (i + j) / 2;
				bitset <MAXN> tmp = now;
				tmp.flip(i), tmp.flip(j), tmp.flip(k);
				if (from.count(tmp) == 0) {
					from[tmp] = now;
					q[++r] = tmp;
					if (tmp == dest) {
						bitset <MAXN> pos = tmp;
						while (pos != 0) {
							bitset <MAXN> tnp = pos ^ from[pos];
							int val = 0;
							x.push_back((val = tnp._Find_first()) + delta);
							y.push_back((val = tnp._Find_next(val)) + delta);
							z.push_back((val = tnp._Find_next(val)) + delta);
							pos = from[pos];
						}
						return;
					}
				}
			}
		}
		printf("NO\n");
		exit(0);
	}
}
int n, a[MAXN];
int main() {
	read(n);
	for (int i = 1; i <= n; i++)
		read(a[i]);
	if (n <= 12) force :: work(a, n, 0);
	else {
		int head = 1, back = n;
		while (back - head >= 12 && a[head] == 0) head++;
		while (back - head >= 12 && a[back] == 0) back--;
		while (back - head >= 12) {
			if (a[head] + a[head + 1] + a[head + 2] == 3) {
				a[head] = a[head + 1] = a[head + 2] = 0;
				x.push_back(head);
				y.push_back(head + 1);
				z.push_back(head + 2);
			} else if (a[back] + a[back - 1] + a[back - 2] == 3) {
				a[back] = a[back - 1] = a[back - 2] = 0;
				x.push_back(back);
				y.push_back(back - 1);
				z.push_back(back - 2);
			} else if ((head + back) % 2 == 0) {
				a[head] = a[back] = 0;
				int mid = (head + back) / 2;
				a[mid] = 1 - a[mid];
				x.push_back(head);
				y.push_back(back);
				z.push_back(mid);
			} else if (a[head + 1] == 1) {
				a[head + 1] = a[back] = 0;
				int mid = (head + 1 + back) / 2;
				a[mid] = 1 - a[mid];
				x.push_back(head + 1);
				y.push_back(back);
				z.push_back(mid);
			} else if (a[back - 1] == 1) {
				a[head] = a[back - 1] = 0;
				int mid = (head + back - 1) / 2;
				a[mid] = 1 - a[mid];
				x.push_back(head);
				y.push_back(back - 1);
				z.push_back(mid);
			} else if (a[head + 2] == 1) {
				a[head + 2] = a[head] = 0;
				a[head + 4] = 1 - a[head + 4];
				x.push_back(head);
				y.push_back(head + 2);
				z.push_back(head + 4);
			} else if (a[back - 2] == 1) {
				a[back - 2] = a[back] = 0;
				a[back - 4] = 1 - a[back - 4];
				x.push_back(back);
				y.push_back(back - 2);
				z.push_back(back - 4);
			} else {
				int tmp = back - 3;
				a[head] = 1 - a[head];
				a[tmp] = 1 - a[tmp];
				int mid = (head + tmp) / 2;
				a[mid] = 1 - a[mid];
				x.push_back(head);
				y.push_back(tmp);
				z.push_back(mid);
			}
			while (back - head >= 12 && a[head] == 0) head++;
			while (back - head >= 12 && a[back] == 0) back--;
		}
		force :: work(a + head - 1, back - head + 1, head - 1);
	}
	printf("YES\n");
	assert((int) x.size() <= n / 3 + 12);
	writeln(x.size());
	for (unsigned i = 0; i < x.size(); i++)
		printf("%d %d %d\n", x[i], y[i], z[i]);
	return 0;
}

**【Div.2 F/Div.1 D】**Familiar Operations

【思路要点】

  • 显然的一点是在本题中,一个数 x a y b . . . z c x^ay^b...z^c 可以被等价地表示为一个可重集 ( a , b , . . . , c ) (a,b,...,c) 。在 1 0 6 10^6 内,本质不同的可重集的个数只有 289 289 个。
  • 一个自然的想法是在这些可重集上跑 F l o y d Floyd 算法,但这个想法是不完善的,因为我们可能会使用到表示的数超过 1 0 6 10^6 的可重集。但这个算法仍旧是有借鉴意义的,根据这个算法的运行结果,我们发现,任何一对可重集在本题中的操作距离至多为 10 10
  • 这启示我们我们只需要考虑所有数字之和在一定范围以内的可重集即可,按照之前的分析,理论上来说,我们需要考虑和在 19 + 10 19+10 以内的所有可重集。但事实证明,我们只需要考虑和在 22 22 以内的可重集即可,这样的可重集的个数是 4508 4508 ,并且本质不同的因数个数为 803 803 。那么,我们只需要从初始的 289 289 个可重集出发,各跑一遍 B F S BFS ,就能够得到将每一个 1 0 6 10^6 内的数的因数个数修改为某值所需的操作步数,询问时枚举修改之后的因数个数即可。
  • 时间复杂度 O ( 1 0 6 + 289 4508 22 + T 803 ) O(10^6+289*4508*22+T*803)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
const int MAXM = 5e3 + 5;
const int INF  = 1e9;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int tot, cnt, prime[MAXN], f[MAXN];
int dist[MAXM][MAXM], realnum[MAXN];
int factors[MAXM];
map <int, int> st; vector <int> pos;
map <vector <int>, int> num;
vector <int> a[MAXM];
void bfs(int from) {
	static int dis[MAXM], q[MAXM];
	memset(dis, -1, sizeof(dis));
	dis[from] = 0, q[0] = from;
	int l = 0, r = 0;
	while (l <= r) {
		int pos = q[l++];
		for (auto x : a[pos])
			if (dis[x] == -1) {
				dis[x] = dis[pos] + 1;
				q[++r] = x;
			}
	}
	for (unsigned i = 1; i <= pos.size(); i++)
		dist[from][i] = 1e9;
	for (int i = 1; i <= cnt; i++)
		chkmin(dist[from][factors[i]], dis[i]);
}
void sieve(int n) {
	for (int i = 2; i <= n; i++) {
		if (f[i] == 0) prime[++tot] = f[i] = i;
		for (int j = 1; j <= tot && prime[j] <= f[i]; j++) {
			int tmp = prime[j] * i;
			if (tmp > n) break;
			f[tmp] = prime[j];
		}
	}
	for (int i = 1; i <= n; i++) {
		int tmp = i;
		vector <int> now;
		now.clear();
		while (tmp != 1) {
			int val = f[tmp], vbl = 0;
			while (tmp % val == 0) {
				vbl++;
				tmp /= val;
			}
			now.push_back(vbl);
		}
		sort(now.begin(), now.end(), [&] (int x, int y) {return x > y; });
		int res = 1;
		for (unsigned j = 0; j < now.size(); j++) {
			for (int k = 1; k <= now[j]; k++)
				res *= prime[j + 1];
		}
		realnum[i] = res;
		if (i == res) bfs(num[now]);
		realnum[i] = num[now];
	}
}
void work(int sum, int k, vector <int> tmp) {
	if (sum == 0) {
		int fac = 1;
		for (auto x : tmp)
			fac *= x + 1;
		if (!st.count(fac)) {
			pos.push_back(fac);
			st[fac] = pos.size();
		}
		num[tmp] = ++cnt;
		factors[cnt] = st[fac];
		for (unsigned i = 0; i < tmp.size(); i++) {
			vector <int> tnp = tmp;
			tnp[i]++; sort(tnp.begin(), tnp.end(), [&] (int x, int y) {return x > y; });
			if (num.count(tnp)) {
				int dest = num[tnp];
				a[dest].push_back(cnt);
				a[cnt].push_back(dest);
			}
			tnp = tmp, tnp[i]--;
			sort(tnp.begin(), tnp.end(), [&] (int x, int y) {return x > y; });
			if (tnp.size() != 0 && tnp.back() == 0) tnp.pop_back();
			if (num.count(tnp)) {
				int dest = num[tnp];
				a[dest].push_back(cnt);
				a[cnt].push_back(dest);
			}
		}
		tmp.push_back(1);
		if (num.count(tmp)) {
			int dest = num[tmp];
			a[dest].push_back(cnt);
			a[cnt].push_back(dest);
		}
		return;
	}
	if (k >= 2) work(sum, k - 1, tmp);
	tmp.push_back(k);
	if (sum >= k) work(sum - k, k, tmp);
}
int main() {
	for (int i = 0; i <= 22; i++)
		work(i, i, vector <int> {});
	sieve(1e6);
	int T; read(T);
	while (T--) {
		int l, r; read(l), read(r);
		l = realnum[l], r = realnum[r];
		int ans = 1e9;
		for (unsigned i = 1; i <= pos.size(); i++)
			chkmin(ans, dist[l][i] + dist[r][i]);
		printf("%d\n", ans);
	}
	return 0;
}

**【Div.1 E】**Rain Protection

【思路要点】

  • 令绳索的两端坐标为 ( x , 0 ) , ( y , h ) (x,0),(y,h) ,我们用点 ( x , y ) (x,y) 来表示该状态。
  • 对于某一滴雨滴,能够接到这滴雨滴的状态会形成一条线段 A i A_i
  • 若当前可以到达的状态的集合为线段 A B AB ,在下一滴雨滴到达之前,绳索的两端能够移动的距离为 d d ,那么在下一滴雨滴到达之时,可以到达的状态的集合即为线段 A B AB 与正方形 ( d , d ) ( d , d ) ( d , d ) ( d , d ) (-d,-d)-(-d,d)-(d,d)-(d,-d) 作闵可夫斯基和后形成的凸包,取与凸包中能够接到这滴雨滴的状态,剩余的部分依旧是一条线段。
  • 二分答案即可,时间复杂度 O ( N L o g V ) O(NLogV)
  • 这道题的思想十分简单,但却较为难以实现,下面笔者来说说自己的实现方式。
  • 求剩余的部分对应的线段时,我们可以将 A i A_i 看做直线,将凸包上所有可能成为边的对角线与 A i A_i 求交,取最远的两个点形成线段,再将该线段框定在 [ 0 , w ] [ 0 , w ] [0,w]*[0,w] 的范围中。
  • 同时,笔者以下这份代码在 C o d e f o r c e s Codeforces 上若将 d o u b l e double 改为 l o n g   d o u b l e long\ double ,则会在几乎所有的 N N 较大的测试点上输出 1 -1 ,但保留 d o u b l e double 就能得到正确结果,对此笔者表示不解。
  • 另外,本题的数据较弱,多为完全随机,或答案为 1 -1 。笔者在调试时复制了一份 A C AC 代码对拍,但却拍出了这份代码的 N = 2 N=2 的错误数据。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 2e5 + 5;
const double eps = 1e-7;
const double pps = 1e-6;
const double INF = 1e99;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct point {double x, y; };
struct line {point a, b; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) {return (point) {a.x * b, a.y * b}; }
double operator * (point a, point b) {return a.x * b.y - a.y * b.x; }
double moo(point a) {return sqrt(a.x * a.x + a.y * a.y); }
point unit(point a) {return a * (1.0 / moo(a)); }
double dist(point a, point b) {return moo(b - a); }
bool equal(double x, double y) {return fabs(x - y) <= eps; }
bool parallel(line x, line y) {return equal((x.b - x.a) * (y.b - y.a), 0); }
double PolarAngle(point a) {return atan2(a.y, a.x); }
point intersect(const line &x, const line &y) {
	double tmp = (y.a - x.a) * (y.b - x.a);
	double tnp = (y.b - x.b) * (y.a - x.b);
	return (x.a * tnp + x.b * tmp) * (1 / (tmp + tnp));
}
bool online(const line &x, const point &y) {
	return equal((y - x.a) * (y - x.b), 0);
}
bool operator < (point a, point b) {
	if (equal(a.x, b.x)) return a.y < b.y;
	else return a.x < b.x;
}
bool operator > (point a, point b) {
	if (equal(a.x, b.x)) return a.y > b.y;
	else return a.x > b.x;
}
int n; double w, h, t[MAXN];
point s, pos[MAXN]; line a[MAXN];
void extend(line &ans, line a, point x, point y) {
	line tmp = (line) {min(x, y), max(x, y)};
	if (parallel(tmp, a)) {
		if (online(a, x)) {
			chkmin(ans.a, x);
			chkmax(ans.b, x);
			chkmin(ans.a, y);
			chkmax(ans.b, y);
		}
		return;
	}
	point pos = intersect(a, tmp);
	if (pos < tmp.a || pos > tmp.b) return;
	chkmin(ans.a, pos);
	chkmax(ans.b, pos);
}
void shrinka(line &ans, line a, point x, point y) {
	line tmp = (line) {min(x, y), max(x, y)};
	if (parallel(tmp, a)) return;
	point pos = intersect(a, tmp);
	if (pos < tmp.a || pos > tmp.b) return;
	chkmax(ans.a, pos);
}
void shrinkb(line &ans, line a, point x, point y) {
	line tmp = (line) {min(x, y), max(x, y)};
	if (parallel(tmp, a)) return;
	point pos = intersect(a, tmp);
	if (pos < tmp.a || pos > tmp.b) return;
	chkmin(ans.b, pos);
}
bool valid(double speed) {
	line now = (line) {s, s};
	for (int i = 1; i <= n; i++) {
		double delta = (t[i] - t[i - 1]) * speed;
		line ans = (line) {(point) {INF, INF}, (point) {-INF, -INF}};
		point x[4] = {now.a, now.a, now.a, now.a};
		point y[4] = {now.b, now.b, now.b, now.b};
		x[0].x -= delta, x[0].y -= delta;
		x[1].x -= delta, x[1].y += delta;
		x[2].x += delta, x[2].y += delta;
		x[3].x += delta, x[3].y -= delta;
		y[0].x -= delta, y[0].y -= delta;
		y[1].x -= delta, y[1].y += delta;
		y[2].x += delta, y[2].y += delta;
		y[3].x += delta, y[3].y -= delta;
		extend(ans, a[i], x[0], x[1]);
		extend(ans, a[i], x[1], x[2]);
		extend(ans, a[i], x[2], x[3]);
		extend(ans, a[i], x[3], x[0]);
		extend(ans, a[i], y[0], y[1]);
		extend(ans, a[i], y[1], y[2]);
		extend(ans, a[i], y[2], y[3]);
		extend(ans, a[i], y[3], y[0]);
		extend(ans, a[i], x[0], y[0]);
		extend(ans, a[i], x[1], y[1]);
		extend(ans, a[i], x[2], y[2]);
		extend(ans, a[i], x[3], y[3]);
		shrinka(ans, a[i], (point) {0, 0}, (point) {0, w});
		if (a[i].a.y < a[i].b.y) shrinka(ans, a[i], (point) {0, 0}, (point) {w, 0});
		else shrinkb(ans, a[i], (point) {0, 0}, (point) {w, 0});
		if (a[i].a.y > a[i].b.y) shrinka(ans, a[i], (point) {w, w}, (point) {0, w});
		else shrinkb(ans, a[i], (point) {w, w}, (point) {0, w});
		shrinkb(ans, a[i], (point) {w, w}, (point) {w, 0});
		if (ans.b < ans.a) return false;
		now = ans;
	}
	return true;
}
double calc(double x, point mid) {
	double ans = mid.x;
	ans += (mid.x - x) / mid.y * (h - mid.y);
	return ans;
}
int main() {
	read(n), read(w), read(h);
	read(s.x), read(s.y);
	for (int i = 1; i <= n; i++) {
		read(t[i]), read(pos[i].x), read(pos[i].y);
		a[i].a = (point) {0, calc(0, pos[i])};
		a[i].b = (point) {w, calc(w, pos[i])};
		if (a[i].a > a[i].b) swap(a[i].a, a[i].b);
	}
	double l = 0, r = 2 * w;
	while (l + pps < r) {
		double mid = (l + r) / 2;
		if (valid(mid)) r = mid;
		else l = mid;
	}
	double ans = (l + r) / 2;
	if (ans > w + eps) printf("-1\n");
	else printf("%.10lf\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/83278746