leetcode第109场双周赛 3 - DP,4 - 01背包!

题目传送门

6931. 访问数组中的位置使分数最大

题意
给你一个数组,初始你位于下标 1 处,你可以往后跳到数组任一下标,但不能往前跳。跳到哪个位置,即可获得下标对应的分数,但如果当前下标的数与跳之前下标的数奇偶性不同,那么你会失去分数 x。询问你能获得的最大分数?

思路
一眼动态规划,那么问题在于怎么规划?
我们贪心的考虑,要让分数最大肯定不能简单的选择奇数或者选择偶数,而是选择最大的跳,奇偶不同时仅存在分数 x 的亏损。那么对于每一个位置,我们都希望它是由前面某个位置跳过来,且能让当前位置取得最大值。又因为奇偶性的问题,所以我们可以记两个数 even 和 odd 来保存当前已经处理段结尾为偶数或者结尾为奇数时的最大值。当前数为偶数时更新 even, 当前数为奇数时更新 odd 。最终答案为 \(max(even, odd)\)
可以再理解理解

代码

#define ll long long
class Solution {
public:
	long long maxScore(vector<int>& a, int x) {
		int n = a.size();
		ll even, odd;
		even = a[0] + ((a[0] % 2 == 0) ? 0 : -x);
		odd = a[0] + ((a[0] % 2 == 0) ? -x : 0);
		for(int i = 1; i < n; ++ i){
			if(a[i] % 2){
				odd = a[i] + max(even - x, odd);
			}else{
				even = a[i] + max(even, odd - x);
			}
		}
		return max(odd, even);
	}
};

6922. 将一个数字表示成幂的和的方案数

题意
就是给你数 n 和数 x,问你有多少种分法,使得 n 表示为互不相同的数的 x 次方的和?结果取余1e9 + 7
比如说:
输入:n = 4, x = 1
输出:2
解释:我们可以将 n 按以下方案表示:

  • $n = 4^1 = 4 $
  • $n = 3^1 + 1^1 = 4 $

思路
没做出来,看的题解。自己的困惑在于,怎么找几个数的 x 次方和为 n ?总不能暴力匹配吧。。。
题解第一眼 01背包。我:嗯??? 这是 01背包?根本想不到啊!
再一理解,嗷!好像可以!把 n 看作背包容量, \(n_i^x\) 视为物品,那不就是看每个物品一次,能不能装满吗?(必须装满,故初始所有 f 均为 0,除了f[0] = 1)
之后就是朴素的 01背包求法,最终答案为 f[n]
很妙很妙很妙,这一重转换没有看出来!

代码

const int mod = 1e9 + 7;
#define ll long long
class Solution {
public:
	int qpow(int a,int x){
		int res = 1;
		while(x){
			if(x & 1) res *= a;
			a *=a;
			x >>= 1;
		}
		return res;
	}
	int numberOfWays(int n, int x) {
		vector<ll> f(n + 5, 0);
		f[0] = 1;
		for(int i = 1; qpow(i, x) <= n ; ++i){
			ll v = qpow(i, x);
			for(int j = n; j >= v; -- j){
				f[j] = (f[j] + f[j - v]) % mod;
			}
		}
		return f[n] % mod;
	}
};
posted on 2023-07-23 23:10  Qiansui  阅读(10)  评论(0编辑  收藏  举报