程序设计思维与实践 Week13 作业

C - TT 的奖励

捡猫咪游戏是这样的,猫咪从天上往下掉,且只会掉在 [0, 10] 范围内,具体的坐标范围如下图所示。
在这里插入图片描述
TT 初始站在位置五上,且每秒只能在移动不超过一米的范围内接住掉落的猫咪,如果没有接住,猫咪就会跑掉。例如,在刚开始的一秒内,TT 只能接到四、五、六这三个位置其中一个位置的猫咪。

喜爱猫咪的 TT 想要接住尽可能多的猫咪,你能帮帮他吗?


Input
多组样例。每组样例输入一个 m (0 < m < 100000),表示有 m 只猫咪。

在接下来的 m 行中,每行有两个整数 a b (0 < b < 100000),表示在第 b 秒的时候有一只猫咪掉落在 a 点上。

注意,同一个点上同一秒可能掉落多只猫咪。m = 0 时输入结束。

Output
输出一个整数 x,表示 TT 可能接住的最多的猫咪数。

Sample Input
6
5 1
4 1
6 1
7 2
7 2
8 3
0
Sample Output
4


思路:dp[i][j]表示第i秒站在j位置能获得最多🐱。显然是一个dp问题。
最先必须在特定位置开始,逆序遍历。
dp[i][j]=max(dp[i-1][k])


#include <iostream>
#include <algorithm>
using namespace std;

int dp[11][100001];
int main()
{
	int m;
	while (cin >> m)
	{
		memset(dp, 0, sizeof(dp));
		if (m == 0) break;
		int maxB = 0;
		for (int i = 0; i < m; i++)
		{
			int a, b; cin >> a >> b;
			dp[a][b]++;
			maxB = max(maxB, b);
		}
		for (int i = maxB - 1; i >= 0; i--)
		{
			for (int j = 0; j <= 10; j++)
			{
				int tmp = dp[j][i + 1];
				if (j > 0) tmp = max(tmp, dp[j - 1][i + 1]);
				if (j < 10) tmp = max(tmp, dp[j + 1][i + 1]);
				dp[j][i] += tmp;
			}
		}
		cout << dp[5][0] << endl;
	}
	return 0;
}

D - TT 的苹果树

在大家的三连助攻下,TT 一举获得了超级多的猫咪,因此决定开一间猫咖,一年后,苹果熟了,到了该摘苹果的日子了。
已知树上共有 N 个节点,每个节点对应一个快乐值为 w[i] 的苹果,为了可持续发展,TT 要求摘了某个苹果后,不能摘它父节点处的苹果。


Input
结点按 1~N 编号。

第一行为 N (1 ≤ N ≤ 6000) ,代表结点个数。

接下来 N 行分别代表每个结点上苹果的快乐值 w[i](-128 ≤ w[i] ≤ 127)。

接下来 N-1 行,每行两个数 L K,代表 K 是 L 的一个父节点。

输入有多组,以 0 0 结束。

Output
每组数据输出一个整数,代表所选苹果快乐值总和的最大值。

输入样例
7
1
1
1
1
1
1
1
1 3
7 4
2 3
4 5
6 4
3 5
0 0
输出样例
5


思路:树的边把树分成大树和子树两部分,问题就可以甩锅给子树
最大收益=本树收益+子树最大收益
要分成当前🍎摘不摘两种情况


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 6000 + 5;
int fa[MAXN], happy[MAXN], n, dp[MAXN][2], root;
vector<int> v[MAXN];

pair<int, int> solve(int r)
{
	int c = 0, b = 0, sz = v[r].size();
	for (int i = 0; i < sz; i++)
	{
		pair<int, int> tmp = solve(v[r][i]);
		b += max(tmp.first, tmp.second);
		c += tmp.first;
	}
	return make_pair(b, c + happy[r]);
}
int main()
{
	while (cin >> n)
	{
		if (n == 0) break;
		memset(fa, 0, sizeof(fa));
		for (int i = 1; i <= n; i++) cin >> happy[i];
		for (int i = 0; i < n - 1; i++)
		{
			int x, y; cin >> x >> y;
			v[y].push_back(x);
			fa[x] = y;
		}
		for (int i = 1; i <= n; i++)
			if (fa[i] == 0) root = i;
		pair<int, int> tmp = solve(root);
		cout << max(tmp.first, tmp.second) << endl;
	}
	return 0;
}

E - TT 的神秘任务3

给定一个环,A[1], A[2], A[3], … , A[n],其中 A[1] 的左边是 A[n]。要求从环上找出一段长度不超过 K 的连续序列,使其和最大。


Input
第一行一个整数 T,表示数据组数,不超过 100。

每组数据第一行给定两个整数 N K。(1 ≤ N ≤ 100000, 1 ≤ K ≤ N)

接下来一行,给出 N 个整数。(-1000 ≤ A[i] ≤ 1000)。

Output
对于每一组数据,输出满足条件的最大连续和以及起始位置和终止位置。

如果有多个结果,输出起始位置最小的,如果还是有多组结果,输出长度最短的。

Sample Input
4
6 3
6 -1 2 -6 5 -5
6 4
6 -1 2 -6 5 -5
6 3
-1 2 -6 5 -5 6
6 6
-1 -1 -1 -1 -1 -1
Sample Output
7 1 3
7 1 3
7 6 2
-1 1 1


思路:

  • 求和问题,用前缀和。
  • 一段范围内的最值问题,用滑动窗口,单调队列
  • 环,加一段绕回来的即可
  • 必须至少要选一个,ans=0特殊处理

#include <iostream>
#include <queue>
using namespace std;
const int MAXN = 1e5 + 5;
int a[MAXN], sum[2 * MAXN], ans, l, r;
int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	int T, N, K;
	cin >> T;
	while (T--)
	{
		cin >> N >> K;
		ans = 0;
		for (int i = 1; i <= N; i++)
		{
			cin >> a[i];
			sum[i] = a[i] + sum[i - 1];
		}
		for (int i = N + 1; i < 2 * N; i++)
			sum[i] = sum[i - 1] + a[i - N];
		deque<int> q;
		q.push_back(0);
		for (int i = 1; i <= 2 * N - 1; i++)
		{
			while (q.size() && sum[q.back()] > sum[i])
				q.pop_back();
			q.push_back(i);
			while (q.size() && i - q.front() > K)
				q.pop_front();
			if (ans < sum[i] - sum[q.front()]
				|| (ans == sum[i] - sum[q.front()] && (i - q.front()) < (r - 1 + 1)))
			{
				ans = sum[i] - sum[q.front()];
				l = q.front() + 1;
				r = i;
			}
		}
		if (ans == 0)
		{
			ans = a[1];
			l = r = 1;
		}
		l = l > N ? l - N : l;
		r = r > N ? r - N : r;
		cout << ans << ' ' << l << ' ' << r << endl;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值