牛客周赛 Round 2

A

小红的环形字符串

题意:

小红有一个环形字符串s,顺时针截取字符串,求要多少种情况等于t。

题解:

环形的字符串可以用s+=s得到。因为本题数据不大,得到环形字符串后就只需要运用BF算法逐个位置判断即可。 

代码:

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<math.h>
using namespace std;
const int N = 2 * 1e5 + 10;
string s, t;
int l, sum;
int main()
{
	cin >> s >> t;
	l = size(s);
	s += s;
	for (int i = 0; i < l; i++)
	{
		int j;
		for (j = 0; j < size(t); j++)
		{
			if (s[i + j] != t[j])
				break;
		}
		if (j == size(t))
			sum++;
	}
	cout << sum;
	return 0;
}

B

相邻不同数字的标记

题意: 

小红有一个用红蓝色标记了的数组,小红可以从中取两个颜色不同相邻的数,求小红能取到的数的和的最大值。

 题解:

本题可以用状态机dp的思想求解。

状态机dp:DP模型——状态机模型_INGg__的博客

 当小红选了前一个数时dp[1][i],当小红未选前一个数时dp[0][i]。

for (int i = 1; i <= n; ++i) {
        dp[0][i] = max(dp[0][i - 1], dp[1][i - 1]);
        if (c[i] != c[i - 1] && i != 1) dp[1][i] = max(dp[0][i - 1] + a[i] + a[i - 1], dp[1][i - 1]);
    }

在每次循环前,如果未选前一个数,那可以讨论选了前一个数的再前一个数和未选前一个数再前一个数的情况哪个更大,dp[0][i]等于更大的那个值。然后再判断如果选了前一个数,和当前数,那么前前个数就不能选,那此时的和为dp[1][i]=dp[0][i-1]+a[i]+a[i-1],如果选当前的数,那么此时的和为dp[1][i-1]。

最后判断选不选最后最后一位数与前一位数哪个大,输出更大的值即可。

代码:

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<math.h>
using namespace std;
const int N = 100010;
long long a[N], dp[2][N]; //dp[i][j]表示前j个数字里,选没选前一个数字
bool st[N];
int n, m, k;
int main()
{

	cin >> n;
	for (int i = 1; i <= n; ++i)
	{
		cin >> a[i];
	}

	string c;
	cin >> c;
	c = "*" + c;

	for (int i = 1; i <= n; ++i) {
		dp[0][i] = max(dp[0][i - 1], dp[1][i - 1]);
		if (c[i] != c[i - 1] && i != 1) dp[1][i] = max(dp[0][i - 1] + a[i] + a[i - 1], dp[1][i - 1]);
	}

	cout << max(dp[0][n], dp[1][n]);
	return 0;
}

C

小红的俄罗斯方块

题意:

小红在8列无穷高的网格玩俄罗斯方块,方块有四种旋转角度,求最后各列的高度。

四种旋转角度如下:

注意所有数据都是合理的,其当同一行填满后方块不会消除。

题解:

直接模拟即可,但是要注意考虑各种情况,

首先当角度为0度时,此时只需要找到b和b+1中最高的一列使h[b],h[b+1]都等于最高的那一列,然后h[b]+=3,h[b+1]++即可。

当角度为90度时要分两种情况讨论:

第一,如果h[b]+1大于等于左边两列,那么h[b]+=2,而左边两列会等于加二后的h[b]。

第二种情况,即h[b]+1小于左边两列,那么此时使h[b]以及左边两列都等于3列中的最大值加一。

当角度为180度时同样分两种情况讨论:

第一,如果h[b+1]+2大于h[b],那么h[b+1]+=3,而h[b]=h[b+1]。

第二,即h[b+1]+2小于h[b],那么此时使h[b+1]=++h[b]。

当角度为270度时,只需找到b,b+1,b+2,三列中最大的一列,使三列都等于三列中的最大值加一即可。

代码:

#include<iostream>
#include<vector>
#include<map>
#include<math.h>
#include<algorithm>
using namespace std;
int n;
int a, b;
int h[10];
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a >> b;
		if (a == 0)
		{
			h[b] = max(h[b], h[b + 1]);
			h[b + 1] = max(h[b], h[b + 1]);
			h[b] += 3;
			h[b + 1] += 1;
		}
		else if (a == 90)
		{
			if (h[b] + 1 >= h[b + 1] && h[b] >= h[b + 2])
			{
				h[b] += 2;
				h[b + 1] = h[b];
				h[b + 2] = h[b];
			}
			else
			{
				h[b] = max(h[b + 1], h[b + 2]);
				h[b + 1] = max(h[b + 1], h[b + 2]);
				h[b + 2] = max(h[b + 1], h[b + 2]);
				h[b]++;
				h[b + 1]++;
				h[b + 2]++;
			}
		}
		else if (a == 180)
		{
			if (h[b + 1] + 2 >= h[b])
			{
				h[b + 1] += 3;
				h[b] = h[b + 1];
			}
			else
			{
				h[b + 1] = h[b];
				h[b]++;
				h[b + 1]++;
			}
		}
		else if (a == 270)
		{
			h[b] = max(h[b], max(h[b + 1], h[b + 2]));
			h[b + 1] = max(h[b], max(h[b + 1], h[b + 2]));
			h[b + 2] = max(h[b], max(h[b + 1], h[b + 2]));
			h[b]++;
			h[b + 1]++;
			h[b + 2] += 2;
		}
	}
	for (int i = 1; i <= 8; i++)
		cout << h[i] << ' ';
	return 0;
}

D

小红打怪

题意:
已知地图上有 n 只怪物,每只怪物的血量是 ai​ ,攻击力是 bi​。小红准备去地图上探险杀怪,她的初始血量为 h。
小红有两个技能:
1. 普通攻击:对一只怪物造成1点伤害。
2. 强力攻击:对一只怪物造成2点伤害。
但是强力攻击是有冷却时间的。释放一个强力攻击后,需要2回合冷却(即释放2次普通攻击后)才能再次释放。
小红每次攻击后,若怪物没有死亡(即血量大于0),小红都会承受一次怪物攻击力的伤害。但是小红可以在战斗开始前喝血药,每个血药可以回复 k 点血量。也就算说, x 瓶血药可以将小红的初始血量提高到 h+x∗k

已知每只怪物都是不可复活的,当小红血量为0或负数时死亡。小红选择打一个怪时,在该怪物被打死之前不会更换目标。

当小红打死一只怪物去寻找另外一只怪物的过程中,我们可以认为强力攻击的冷却已经恢复完毕。

请问,小红初始带了 x 瓶血药时,最多可以击杀多少只怪物?

上述问题会重复 q次,每次询问都是独立的,小红初始的血瓶数量可能不同。

题解:

直接模拟的话时间复杂度为O(n^{2})会导致超时,此时可用前缀和以及二分优化。

二分:C++-二分查找库函数

小红每次攻击怪物时,每消耗怪物4点血量,怪物能攻击三次。

所以当怪物血量能被4整除时,怪物发动3*怪物血量/4。

当不能被整除时,余数为1,2时,小红还需要攻击一次所以怪物也再攻击一次,余数为3时小红攻击两次。怪物攻击1次。

因为小红是先手。所以怪物的最后一击打不出来就被击杀。所以怪物的攻击次数要减去1。

求出击杀每只怪物所需的血量后,将其按从小到大的顺序排序,再求前缀和。

求出前缀和后运用二分查找找出小红能击杀的怪物个数。

代码:

#include<iostream>
#include<vector>
#include<map>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll n, h, k, q;
ll a[N], b[N], r[N], s[N];
vector<ll>hit;
void init()
{
	for (int i = 1; i <= n; i++)
		s[i] = s[i - 1] + hit[i - 1];
}
int main()
{
	cin >> n >> h >> k;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i] >> b[i];
		ll hp = a[i] / 4 * 3;
		ll	sp = a[i] % 4;
		if (sp == 0)hp += 0;
		else if (sp <= 2)hp++;
		else hp += 2;
		hit.push_back((hp - 1) * b[i] * 1ll);
	}
	sort(hit.begin(), hit.end());
	cin >> q;
	init();
	for (int i = 1; i <= q; i++)
	{
		cin >> r[i];
		ll sum;
		sum = lower_bound(s + 1, s + n, r[i] * k + h) - s - 1;
		cout << sum << ' ';
	}
	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值