链接:https://ac.nowcoder.com/acm/contest/5968/A
来源:牛客网
题目描述
牛市,一个拥有悠久历史的城市,2333年考古学家在牛市发现了一个神秘的遗迹,这些勇敢而智慧的古队员准备进入这个遗迹,但要进入这个遗迹就需要通过一段天梯。而登上天梯必须要按照它要求的方法,否则就无法登上。它要求的方法为:
1.可以直接登上比当前位置高1个单位高度的天梯。
2.可以从当前阶梯往下退一级天梯(第一级天梯除外)。
3.在连续退k步后,跳跃一次,跳跃的高度不超过2^k。比如说你现在位于第i级天梯,且之前从第i+k级天梯退下来,此时你可以跳到高度不超过(当前高度+ 2^k)的任何一级天梯。每一次跳跃只算一次移动哦!
开始的时候考古小队在第一级天梯。请你计算出最少的移动步数以登上最高一级天梯。
为何考古搞得跟游戏历险一样?牛市一定是一个魔性的城市!
输入描述:
第1行:一个整数N,表示天梯级数。
第2行:N个整数,依次为每层天梯梯的高度,保证递增。
输出描述:
一个整数,如果能登上天梯,输出最小步数,否则输出-1。
示例1
输入
复制
5
0 1 2 3 6
输出
复制
7
说明
1≤N≤200。 每级阶梯高度不超过2^31-1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[500];
int a[500];
int qpow(int x, int n)
{
int sum = 1;
while (n)
{
if (n & 1)
{
sum *= x;
}
x *= x;
n >>= 1;
}
return sum;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
memset(dp, 0x3f, sizeof dp);
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
dp[1] = 0;
for (int i = 2; i <= n; i++)
{
bool f = 1;
if (a[i] == a[i - 1] + 1)
{
dp[i] = dp[i - 1] + 1;
f = 0;
}
for (int j = 1; j < i; j++)
{
for (int r = j; r >= 1; r--)
{
if (a[i] <= a[r] + qpow(2, j - r))
{
dp[i] = min(dp[i], dp[j] + j - r + 1);
f = 0;
break;
}
}
}
if (f)
{
cout << -1 << endl;
return 0;
}
}
cout << dp[n] << endl;
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/5968/B
来源:牛客网
题目描述
考古队员发现,牛市之所以会有那么多古老遗迹,是因为牛市曾经遭遇过一场几乎毁灭了他的流星雨,那场流星雨中流星体积很大,无法在撞击到地面前燃烧完,所以对牛市几乎造成了毁灭性的打击,但是,我们牛市的先民也是很厉害的,他们对于流星雨的预报虽然没有提前太多的时间但是详细到了每颗流星坠落的位置,所以虽然牛市在那一场流星雨之后满目疮痍,但是牛市的百姓大多都存活了下来。因为自然环境受到了巨大的破坏,他们记录下了这段历史搬到其他的地方繁衍生息,很多代人之后,牛市的自然环境有了恢复,他们后代中的一些人又搬了回来,逐渐建成了现在的牛市。这段历史被遗忘被尘封多年,但终于还是没有被遗忘……
根据遗迹中某个记载,当时先民们预报了一共有M颗(1≤M≤50,000)会坠落,他们将牛市划分成网格,他们预报其中第i颗流星会在时刻Ti(0≤Ti ≤1,000)砸在坐标为(Xi, Yi)(0<=Xi<=300,0<=Yi <=300)的格子里。流星的力量会将它所在的格子,以及周围4个相邻的格子都化为焦土,在整个流星雨结束之前,这些格子都将无法行走站立。
现在有一个家族,在0时刻在0行0列的格子里,因为道路和建筑的原因,他们只能平行于坐标轴行动,每1个时刻,他们能移动到相邻的4个格子中的任意一个,当然这个格子要没有被撞击烧焦才行。(也就是说如果一个格子在时刻t被流星撞击或烧焦,那么他们只能在t之前的时刻在这个格子里出现。)
请你计算,这个家族是否在这场流星雨中幸存(移动到了一个没有被撞击或者烧焦的格子里一直待到流星雨结束),如果幸存,他们最少要花多少时间才移动到安全的格子里。
注:虽然流星只是砸在x,y坐标300的范围内,但是我们可以认为牛市在整个第一象限之内,即移动过程中x和y都可以超出300(但不能为负)。
输入描述:
第1行: 1个正整数:M
第2…M+1行: 第i+1行为3个用空格隔开的整数:Xi, Yi,Ti
输出描述:
输出1个整数,即这个家族逃生所花的最少时间。如果这个家族无论如何都无法在流星雨中存活下来,输出-1
示例1
输入
复制
4
0 0 2
2 1 2
1 1 2
0 3 5
输出
复制
5
说明
这个家族最后待在了(0,5),(1,4)或者(2,3)这三个格子其中之一,他们都可以在5单位时间到达
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int x, y, t;
node(int x, int y, int t) : x(x), y(y), t(t) {}
};
int vis[305][1005], g[305][305];
int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};
int bfs()
{
queue<node> q;
q.push(node(0, 0, 0));
vis[0][0] = 1;
while (!q.empty())
{
node u = q.front();
q.pop();
if (g[u.x][u.y] == 0x3f3f3f3f)
{
return u.t;
}
for (int i = 0; i < 4; i++)
{
int tx = u.x + dx[i];
int ty = u.y + dy[i];
if (tx < 0 || ty < 0 || vis[tx][ty])
continue;
if (u.t + 1 >= g[tx][ty])
continue;
vis[tx][ty] = 1;
q.push(node(tx, ty, u.t + 1));
}
}
}
int main()
{
int m, x, y, t;
cin >> m;
memset(g, 0x3f, sizeof(g));
for (int i = 1; i <= m; i++)
{
cin >> x >> y >> t;
g[x][y] = min(t, g[x][y]);
for (int j = 0; j < 4; j++)
{
int tx = x + dx[j];
int ty = y + dy[j];
if (tx < 0 || ty < 0)
continue;
g[tx][ty] = min(g[tx][ty], t);
}
}
cout << bfs() << endl;
}
C
链接:https://ac.nowcoder.com/acm/contest/5968/C
来源:牛客网
题目描述
牛市的幸存的先民在流星雨之后就忍痛离开了这片土地,选择迁徙,在迁徙的途中,他们需要渡过一条河。因为牛市的树木在流星雨中被严重破坏,所以他们只造出了一艘小船,船太小了,一次只能乘坐两人。
牛市的先民们每个人划船的速度都不尽相同,所以每个人都有一个渡河时间T,为了保证船的平衡,当穿上有两个人的时候,需要他们按照慢的那个人的速度划船,也就是说船到达对岸的时间等于船上渡河时间长的那个人的时间。
现在已知N个人的渡河时间T,请问最少要花费多少时间,才能使所有人都过河。
输入描述:
输入文件第一行为先民的人数N(N\leq 100000)(N≤100000),以下有N行,每行一个整数为每个人的渡河时间。
输出描述:
输出文件仅包含一个数,表示所有人都渡过河的最少渡河时间。
示例1
输入
复制
4
5
7
11
16
输出
复制
42
说明
首先1,2先到河对岸花费7,然后1回来花费5,3,4到河对岸花费16,2回来花费7,1,2再到河对岸花费7
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int a[maxn], n;
int ans;
int dp[maxn];
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a, a + n);
memset(dp, 0x3f, sizeof(dp));
dp[1] = a[1];
dp[2] = a[2];
for (int i = 3; i <= n; i++)
{
dp[i] = min(dp[i - 1] + a[1] + a[i], dp[i - 2] + a[2] + a[i] + a[1] + a[2]);
}
cout << dp[n] << endl;
}
E
链接:https://ac.nowcoder.com/acm/contest/5968/E
来源:牛客网
题目描述
牛牛在牛市的旅游纪念商店里面挑花了眼,于是简单粗暴的牛牛决定——买最受欢迎的就好了。
但是牛牛的背包有限,他只能在商店的n个物品里面带m个回去,不然就装不下了。
并且牛牛希望买到的纪念品不要太相似,所以导购小姐姐帮助牛牛把纪念品全部排成了一行,牛牛只需要让选出来要买的m个物品中任意两个的位置差都大于等于k就行了。
现在告诉你这n个物品排成一行之后的受欢迎程度(可能是负数),求牛牛带回去的m个物品的最大欢迎度之和。
输入描述:
第一行三个数n,m,k
接下来一行,有n个整数,是n个物品按顺序的受欢迎程度。
输出描述:
输出一个数为题目所求的最大和
示例1
输入
复制
4 2 2
2 4 -6 1
输出
复制
5
#include <bits/stdc++.h>
using namespace std;
int n, m, k, f[10005][105], v[10005]; //f[i][j]表示从前i个物品中选j个物品
int main()
{
memset(f, 128, sizeof f);
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; ++i)
scanf("%d", v + i), f[i][0] = 0;
f[1][1] = v[1];
for (int i = 1; i <= k; ++i)
f[i][1] = max(f[i - 1][1], v[i]);
for (int i = k + 1; i <= n; ++i) //最小有K+1个东西,最多有n个东西
for (int j = 1; j <= m; ++j)
f[i][j] = max(f[i - k][j - 1] + v[i], f[i - 1][j]);
printf("%d", f[n][m]);
}