CSDN竞赛63期题解

总结

这次竞赛由三道老题目和一道表述不清的题目构成,老题目尝试新的方法去做,慢悠悠的写着也花了不少时间。最后一道虽然表述不清,但是如果仔细斟酌也是可以AC的。由于第一名的书籍之前拿过了,不太感兴趣也就没有执着于AC,当然也没有故意少通过几个用例去控制排名。对C站竞赛的态度基本是:遇见做过的题目尝试用新的方法去求解,遇见有问题的题目尝试去猜测出题人的意图。大多数同学看见最后一道表述不清就直接骗点分交卷了,尝试猜测题意比再打一遍老题目的代码还是更有意义一点的。

题目列表

1.小玉家的电费

题目描述

夏天到了,各家各户的用电量都增加了许多,相应的电费也交的更多了。小玉家今天收到了一份电费通知单。小玉看到上面写:据闽价电[2006]27号规定,月用电量在150千瓦时及以下部分按每千瓦时0.4463元执行,月用电量在151~400千瓦时的部分按每千瓦时0.4663元执行,月用电量在401千瓦时及以上部分按每千瓦时0.5663元执行;小玉想自己验证一下,电费通知单上应交电费的数目到底是否正确呢。请编写一个程序,已知用电总计,根据电价规定,计算出应交的电费应该是多少。

输入描述:

输入一个整数,表示用电总计(单位以千瓦时计),不超过10000。

输出描述:

输出一个数,保留到小数点后1位(单位以元计,保留到小数点后1位)。

输入样例:

267

输出样例:

121.5

分析

考过的签到题,按照规则模拟下就可以了。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int main() {
	int n;
	cin>>n;
	double res = 0;
	if (n <= 150) res += n * 0.4463;
	else {
		res += 150 * 0.4463;
		if (n <= 400) res += (n - 150) * 0.4663;
		else {
			res += 250 * 0.4663;
			res += (n - 400) * 0.5663;
		}
	}
	printf("%.1lf",res);
	return 0;
}

2.饿龙咆哮-逃离城堡

题目描述

饿龙咆哮,饿偶!饿偶!饿偶偶!
小艺酱误入龙族结界,被恶龙带回城堡,准备当作新娘。
可是小艺酱怎么可能嫁给一个吃不饱穿不好的饿龙呢?
小艺酱决定逃离城堡,逃离龙族结界,总路程为c。
小艺酱的速度是vp,饿龙速度为vd。饿龙会在t小时后发现小艺酱出逃。
小艺酱担心自己跑不出去,准备了好多珍宝。
每当饿龙追上自己的时候小艺酱就会丢下一个珍宝,饿龙捡到珍宝会返回自己的城堡进行研究,研究f小时后,再出城堡追赶小艺。
小艺想知道自己至少需要丢多少珍宝才能让自己安全逃出结界。

输入描述:

输入整数vp,vd,t,f,c。(1<=vp,cd<=100,1<=t,f<=10,1<=c<=1000)

输出描述:

输出答案。

输入样例:

1
2
1
1
10

输出样例:

2

分析

还是考过的题目,对python选手更加友好,因为饿龙追上小艺的时候可能不是某个整点,python选手可以无视数据类型进行模拟,而C++就需要用浮点数存储路程,否则不能AC。

基本思路就是先求出最开始 t t t小时后两者的距离,当小艺还没到达终点时候,计算下饿龙要多久才会追到小艺。一旦过了这么久小艺没到终点,就需要扔下一个珍宝。饿龙将返回城堡加上停留 f f f小时(这里的停留时间不要漏了),小艺将继续前行这么久,之后饿龙再次出发,重复这个过程直至小艺到达终点。

代码

#include <iostream>
#include <string>
using namespace std;
int solution(int vp, int vd, int t, int f, int c) {
	int res = 0;
	double s = vp * t;
	int l = 0;
	if (vp >= vd) return 0;
	while(s < c) {
		double t1 = s / (vd - vp);
		s += t1 * vp;
		if (s < c) {
			res++;
			s += (t1 + f) * vp;
		}
	}
	return res;
}
int main() {
	int vp;
	int vd;
	int t;
	int f;
	int c;
	std::cin>>vp;
	std::cin>>vd;
	std::cin>>t;
	std::cin>>f;
	std::cin>>c;
	int result = solution(vp, vd, t, f, c);
	std::cout<<result<<std::endl;
	return 0;
}

3.收件邮箱

题目描述

已知字符串str,str表示邮箱的不标准格式。
其中”.”会被记录成”dot”,”@”记录成”at”。
写一个程序将str转化成可用的邮箱格式。(可用格式中字符串中除了开头结尾所有”dot”,都会被转换,”at”只会被转化一次,开头结尾的不转化)

输入描述:

输入字符串str.(1<=strlen(str)<=1000)

输出描述:

输出转化后的格式。

输入样例:

mxyatoxcoderdotcom

输出样例:

mxy@oxcoder.com

分析

考过很多次了,这次尝试换个方法做,才注意到C++ string的replace函数竟然不支持替换指定字符串,最后还是直接模拟了,调了下substr函数减少下代码量。

代码

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <regex>
using namespace std;
std::string solution(std::string str) {
	int n = str.size();
	string s;
	s += str[0];
	bool flag = true;
	for(int i = 1; i < n; i++) {
		if (i < n - 3 && str.substr(i, 3) == "dot") {
			s += ".";
			i += 2;
		} else if (flag && i < n - 2 && str.substr(i, 2) == "at") {
			s += "@";
			i++;
			flag = false;
		} else {
			s += str[i];
		}
	}
	return s;
}
int main() {
	std::string str;
	getline(std::cin, str);;
	std::string result = solution(str);
	std::cout<<result<<std::endl;
	return 0;
}

4.寻找宝藏山

题目描述

一天,你去了一个神秘的森林,在那里你遇到了一个神秘的老人。他告诉你,森林里有一座宝藏山,但是要想到达宝藏山,你必须先通过一些森林的入口。

这个老人给你了一张地图,地图上有若干个入口和宝藏山,每个入口都有一个花费。你可以从任意一个入口开始,然后经过一些入口,最终到达宝藏山。但是你有一个限制,你只能走 K K K 步,如果走的步数超过了 K K K,那么你就无法到达宝藏山,也就无法获得宝藏。

你必须实现一个程序,接受用户输入的地图信息,并计算出,你能够到达宝藏山的最小花费。

输入描述:

第一行包含三个整数 N N N M M M K K K,表示入口的个数、边的个数和最多走的步数。

接下来 M M M 行,每行包含三个整数 A A A B B B C C C,表示一条从 A A A B B B 的有向边,边权为 C C C

输出描述:

输出一行,包含一个整数,表示你能够到达宝藏山的最小花费。

输入样例:

5 10 6
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
5 2 3
2 3 4
2 1 1
2 3 4
3 4 5

输出样例:

1061109567

分析

这次比赛的唯一一道没考过的,参加这么多次,遇见题意表述不清应该见怪不怪了,内心毫无波澜的同时尝试去猜下出题人想搞啥事。

题目给定了 n n n个入口,让我们从任意一个入口出发,前进不到 k k k步,到达宝藏山。乍一看没多大问题,唯一的问题就是没告诉我们宝藏山在哪。题目唯一的信息就是告诉我们经过了一些入口最终会到达宝藏山,由此推导宝藏山应该在这些入口之中,那么我从任意入口出发,尝试走遍所有能到达的入口,如果走过的入口数正好是 n n n,说明走完了,应该就可以找到宝藏山了。这样做可以通过四成的用例。

对于用例给出的输出,熟悉图论的选手应该不会陌生,给int类型变量 m e m s e t memset memset 0 x 3 f 0x3f 0x3f就可以得到这个数了,表示 I N F INF INF。既然前面那种求哈密顿回路的思想不能通过所有用例,根据题目问的最小花费以及走k步的限制,可以猜测是想求有边数限制的最短路。我直接求出1号入口到 n n n号入口的最短距离,按照AcWing 853 有边数限制的最短路来做最后通过了九成的用例,考虑负权边以及自环之类的也没有AC。

除了没有告诉我们最短路的终点在哪外,另一个模糊的地方在花费上,没有说明边权的单位是步数,如果边权是步数,那么直接求1到 n n n的最短代价,判断下是否大于 k k k即可。有可能题目表达的就是这种含义,比赛时没有尝试这种思路。另一种理解就是说走到另一个相连的入口算1步,走不超过 k k k步到达终点,然后再在里面求下走过的边权之和的最小值,我采取的就是这种做法,有一个用例没有通过,也没有继续深究了。

代码

#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 100005;
int idx;
typedef pair<int,int> PII;
map<PII,int> mp;
int n,m,k;
int d[N], b[N];
struct Node {
	int x,y,w;
} edge[N];
int bellman_ford() {
	memset(d,0x3f,sizeof d);
	d[1] = 0;
	for(int i = 0; i < k; i++) {
		memcpy(b, d,sizeof b);
		for(int j = 0; j < idx; j++) {
			auto e = edge[j];
			d[e.y] = min(d[e.y], b[e.x]+e.w);
		}
	}
	if (d[n] > 0x3f3f3f3f / 2) return 0x3f3f3f3f;
	return d[n];
}
int main() {
	cin>>n>>m>>k;
	int a,b,c;
	for (int i = 0; i < m; i++) {
		cin>>a>>b>>c;
		if (mp.count({a,b})) mp[ {a,b}] = min(mp[ {a,b}], c);
		else mp[ {a,b}] = c;
	}
	for (auto t : mp) {
		a = t.first.first, b = t.first.second;
		c = t.second;
		edge[idx++] = {a, b, c};
	}
	cout<<bellman_ford()<<endl;
	return 0;
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值