KEYENCE Programming Contest 2024(AtCoder Beginner Contest 374)题解ABCDE

A - Takahashi san 2

题意:输入一个字符串 S,如果它以 san 结尾,则输出 Yes,否则输出 No

思路:模拟后三位即可

	string s;
	cin >> s;
	if(s.substr(sz(s)-3,3) == "san")cout <<"Yes\n";
	else cout <<"No\n";
	return 0;	

B - Unvarnished Report

题意:给定两个字符串 s 和 s1,请求出两个字符串中的字符第一次不相同的位置是哪里。如果两个字符串完全相同,请输出 0。

思路:模拟即可

	string q , w;
	cin >> q >> w;
	if(q == w)cout <<"0\n";
	else{
		if(sz(q) > sz(w))swap(q , w);
		for(int i = 0;i<sz(q);i++){
			if(q[i]!=w[i]){
				cout << i + 1<< endl;
				return 0;
			}
		}
		cout <<sz(q) + 1 << endl;
	}

C - Separated Lunch

题意:

总部有 N 个部门,第 i 个部门 (1≤i≤N) 的人数为 Ki​ 。

将每个部门分配到 A 组或 B 组,让每个组里面的所有人在同一时间午休,并确保 A 组和 B 组的午休时间不重叠,求同一时间午休的最大人数的最小值。
换句话说,求分配给 A 组的部门总人数和分配给 B 组的部门总人数中较大者的最小值。

思路:观察到N < 20,枚举所有情况DFS即可

// Code Start Here	
	int n;
	cin >> n;
	vector<int> a(n);
	for(int i = 0;i<n;i++)cin >> a[i];
	int ans = INF;
	int sum = 0;
	for(int i = 0;i<n;i++)sum +=a[i];
	auto dfs = [&](auto dfs,int deep,int now){
		if(deep == n){
			ans = min(ans,max(now,sum - now));
			return;
		}
		dfs(dfs,deep+1,now + a[deep]);
		dfs(dfs,deep+1,now);
	};
	dfs(dfs,0,0);
	cout << ans << endl;
	return 0;	

题意:

有一台打印机,它可以通过发射激光束在 xy 平面上打印线段。

  • 最开始时,激光位于坐标 (0, 0)。

  • 要打印一条线段时,打印机必须遵循以下流程:

    • 首先,将激光从当前位置移动到要打印线段的一个端点。
      • 可以任选一个端点移过去准备打印。
    • 然后,发射激光,打印这条线段。将激光从一个端点沿直线移动到另一个端点。
      • 在这个过程中不允许关闭激光。
  • 不发射激光时,可以以每秒 S 个单位的速度向任何方向移动激光的位置。

  • 发射激光时,可以以每秒 T 个单位的速度沿着线段移动激光的位置。

  • 除移动激光的位置外,其它所有操作所需的时间都忽略。

高桥希望用这台打印机打印 N 条线段。 第 i 个线段连接坐标 (Ai​, Bi​) 和 (Ci​, Di​)。 请注意,有几条线段可能会重叠,但每次都必须打印所有线段的重叠部分。

当他以最佳方式操作印刷机时,完成所有线段的印刷至少需要多少秒?

思路:一个比较麻烦的模拟题,注意到需要枚举线段的先后顺序,然后每个线段有两种画的方式,时间复杂度很好,但是观察到最多只有六条线段,所以直接枚举+DFS即可

// Code Start Here	
	int N,S,T;
	cin >> N >> S >> T;
	vector<int> A(N), B(N), C(N), D(N);
	for (int i = 0; i < N; i++) {
		cin >> A[i] >> B[i] >> C[i] >> D[i];
	}
	double ans = INF;
	vector<bool> vis(N);
	auto dfs = [&](auto &self, int x, int y, double sum = 0.0, int c = 0) {
		if (c == N) {
			ans = min(ans, sum);
			return;
		}
		for (int i = 0; i < N; i++) {
			if (vis[i]) {
				continue;
			}
			//hypot函数返回原点到给定坐标的欧几里得距离
			double d1 = hypot(A[i] - x, B[i] - y);
			double d2 = hypot(C[i] - x, D[i] - y);
			double d0 = hypot(A[i] - C[i], B[i] - D[i]);
			vis[i] = true;
			self(self, C[i], D[i], sum + d1 / S + d0 / T, c + 1);
			self(self, A[i], B[i], sum + d2 / S + d0 / T, c + 1);
			vis[i] = false;
		}
	};
	dfs(dfs,0,0,0);
	cout << point(20) << ans <<endl;
dfs(dfs, 0, 0);
cout << fixed << setprecision(20) << ans << endl;

E - Sensor Optimization Dilemma 2

题意:

我们有 N 个工序,每个工序需要达到至少 u的产能。对于工序 i:有两种机器可供选择:

机器 Si​:每台每天可处理 Ai​ 个产品,价格为 Pi​;

机器 Ti​:每台每天可处理 Bi​ 个产品,价格为 Qi​。

可以任意购买这两种机器的任意数量,目标是让每个工序的总产能达到 u(即总产能为各工序产能的最小值),并且全局花费不超过预算 X 日元。

我们的目标是求出在预算 X 内,能够达到的最大产能 u。

思路:

由于 u 的取值范围很大(最高可达 10^9),我们采用二分搜索确定最大的可行 u。对于每个候选的 u,需要判断是否能在预算内实现每个工序的产能不少于 u。

对于工序 i,我们需要用两种机器的组合来达到至少 u 的产能。令购买x 台 Si​ 和 y 台Ti​ 后,总产能为

x*Ai​+y*Bi​≥u,

总花费为

x*Pi​+y*Qi​.

所以模型可以转化为:在满足产能要求的前提下,如何组合购买 Si​ 和 Ti​ 使得花费最小?

为了方便后续讨论,代码先对每个工序判断两种机器的性价比:

  • 机器 Si​ 的性价比:Ai/Pi
  • 机器 Ti​ 的性价比:Bi/Qi

如果发现 Ai/Pi  <Bi/Qi ,即 Ai×Qi<Bi×Pi,则交换两种机器的信息。这样交换后,我们保证机器 Si​ 的单位产能成本不高于机器 Ti​(即 S 更“划算”)。通常我们希望尽可能多地使用更划算的 S,但有时因为 S 的产能增量较大,可能导致购买 S 时“过量”,此时适当使用 T 来填补余缺可能会更便宜。

然后很明显的,我们可以暴力枚举 T 的台数,二分搜索求最大u即可

// Code Start Here	
	int N, X;
	cin >> N >> X;
	
	vector<int> A(N), B(N), P(N), Q(N);
	for (int i = 0; i < N; i++) {
		cin >> A[i] >> P[i] >> B[i] >> Q[i];
		if (A[i] * Q[i] < B[i] * P[i]) {
			swap(A[i], B[i]);
			swap(P[i], Q[i]);
		}
	}
	auto check = [&](int u) {
		int ans = 0;
		for (int i = 0; i < N; i++) {
			int res = 1E18;
			for (int j = 0; j <= 100; j++) {
				int v = j * Q[i];
				int need = u - j * B[i];
				if (need > 0) {
					v += 1LL * (need + A[i] - 1) / A[i] * P[i];
				}
				res = min(res, v);
			}
			ans += res;
		}
		return ans <= X;
	};
	int l = 0, r = 1E9;
	while (l < r) {
		int x = l + r + 1 >> 1;
		if (check(x)) {
			l = x;
		} else {
			r = x - 1;
		}
	}
	cout << l <<endl;
	return 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值