当前位置: 首页 > article >正文

CSP-J 2023 T1小苹果 T2公路

文章目录

    • [CSP-J 2023] T1 - 小苹果
    • [CSP-J 2023] T2 - 公路

[CSP-J 2023] T1 - 小苹果

每隔两个苹果取一个苹果,也就是每三个苹果取一个苹果,此时肯定需要在与模 3 3 3有关的基础上进行分类讨论:

  • n % 3 = = 0 n\%3==0 n%3==0时,此时n可以整除3,每次可以取 n 3 \frac{n}{3} 3n个苹果。
  • n % 3 ! = 0 n\%3!=0 n%3!=0时,每次可以取 ⌈ n 3 ⌉ \lceil \frac{n}{3}\rceil 3n个苹果。

此时我们可以使用循环来模拟拿苹果的过程,不需要知道每次拿的是哪几个苹果,只需要知道每次拿了几个苹果,每次更新苹果的数量,当苹果被取完时循环结束。 a n s ans ans即为拿苹果的次数。

while (n) {
	ans++;
	if (n % 3 == 0) n = n - n / 3;
	else n = n - (n / 3 + 1);
}

除此之外,题目还要求编号为 n n n的苹果是第几次被拿走的,由于我们每次拿的是最左边的苹果,当编号为 n n n的苹果在某一块的最左侧时,此时就可以拿到这个编号为 n n n的苹果,也就是当 n % 3 = = 1 n\%3==1 n%3==1时。

最后可以检查一下复杂度,每次都会拿走至少 1 3 \frac{1}{3} 31的苹果,也就是苹果每次会变成其原来的 2 3 \frac{2}{3} 32倍, n n n最大是 1 e 9 1e9 1e9,设最后执行了 t t t次,则 1 e 9 ∗ ( 2 3 ) t = 1 1e9*(\frac{2}{3})^t=1 1e9(32)t=1 t t t的值是 50 50 50左右,复杂度完全没问题。

#include <bits/stdc++.h>

using namespace std;
int n, ans, t;

int main(int argc, char const *argv[]) {
	cin >> n;
	while (n) {
		ans++;
		if (n % 3 == 1 and !t) t = ans; 
		if (n % 3 == 0) n = n - n / 3;
		else n = n - (n / 3 + 1);
	}
	cout << ans << " " << t << endl;
}

[CSP-J 2023] T2 - 公路

本题的油箱无限大,所以当一个点的油价很便宜时,我们要在这个点买足够多的油,这个足够多的限制在哪里?就是能够支撑我们到下一个更便宜的点。至此思路就很明显了,在起点处是必须要买油的,当遇到一个比起点更低价格的点时,计算这两个点之间的距离(前缀和),用起点的价格买足够多的油,来到这个点之后继续向后寻找更便宜的油。

要注意的点是买的油一定是整数,例如点 1 1 1与点 2 2 2的距离是 10 10 10,每升油能让我们走 4 4 4,在起点处就必须买 3 3 3升油( 3 ∗ 4 = 12 > 10 3*4=12>10 34=12>10)如果点 1 1 1与点 2 2 2的距离是 12 12 12,我们还是需要买 3 3 3升油,所以要买的油的数量 x x x与距离 d i s t a n c e distance distance的关系是 x = ⌈ d i s t a n c e d ⌉ x=\lceil\frac{distance}{d}\rceil x=ddistance,具体写代码时,为了避免浮点数或者取整操作,我们可以使 x = d i s t a n c e + d − 1 d x=\frac{distance+d-1}{d} x=ddistance+d1,这个式子和上式是等价的,例如 10 + 4 − 1 4 = 3 \frac{10+4-1}{4}=3 410+41=3 12 + 4 − 1 4 = 3 \frac{12+4-1}{4}=3 412+41=3。另外,到达点 2 2 2之后我们还剩 2 2 2升油,这 2 2 2升油是可以继续用的。

最终车一定要开到 n n n号点,所以如果在最后一个点时没有更新更便宜的油价,那么终点到上一个便宜点之间的距离是会被忽略的。所以最后要加一下开到终点的花费。

#include <bits/stdc++.h>
#define A 100010

using namespace std;
typedef long long ll;
int n, v[A], a[A];
ll ans, d, sum[A];

int main(int argc, char const *argv[]) {
	cin >> n >> d;
	for (int i = 2; i <= n; i++) {
		scanf("%d", &v[i]);
		sum[i] = sum[i - 1] + v[i];
	}
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int pos = 1;
	ll oil = 0, leftoil = 0, minn = a[1];
	for (int i = 2; i <= n; i++) {
		if (a[i] < minn) {
			oil = (sum[i] - sum[pos] - leftoil + d - 1) / d;
			leftoil += oil * d - (sum[i] - sum[pos]);
			ans += oil * minn;
			minn = a[i];
			pos = i;
		}
	}
	ans += (sum[n] - sum[pos] - leftoil + d - 1) / d * minn;
	cout << ans << endl;
}

由于做法中出现了乘法,所以代码写出之后需要关注一下是否会爆 i n t int int,每个变量的数据范围都是 1 e 5 1e5 1e5,前缀和 s u m [ n ] = n ∗ v [ i ] = 1 e 10 sum[n]=n*v[i]=1e10 sum[n]=nv[i]=1e10会爆 i n t int int o i l ∗ d oil*d oild o i l ∗ m i n n oil*minn oilminn也有可能爆 i n t int int,需要给相应的变量开上 l o n g   l o n g long\ long long long


http://www.kler.cn/news/331082.html

相关文章:

  • 一、Spring Boot集成Spring Security之自动装配
  • Gazebo安装,ubuntu22
  • Linux云计算 |【第四阶段】RDBMS1-DAY3
  • django创建一个新的应用
  • 什么是 Angular 开发中的 Dumb components
  • PowerBI概述
  • 滚雪球学Oracle[4.3讲]:PL/SQL控制结构与循环的深入解析与优化
  • python三局两胜游戏
  • 点评项目-3-登录成功后加载登录页面
  • Java String底层源码分析
  • 项目管理系统如何实现项目申报流程自动化?
  • 【redis-04】Redisson实现分布式锁实战和源码剖析
  • 基于ESP8266—AT指令连接阿里云+MQTT透传数据(3)
  • 2022浙江省赛G I M
  • el-table按照查询条件再对应行数据进行高亮,并可以定位到某行
  • C++20中头文件concepts的使用
  • 如何设置MySQL分布式架构主键ID,为什么不能使用自增ID或者UUID做主键?
  • 问题解决实录 | bash 中 tmux 颜色显示不全
  • 接口隔离原则(学习笔记)
  • Vue3轻松实现前端打印功能