956. 最高的广告牌
你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。
你有一堆可以焊接在一起的钢筋 rods
。举个例子,如果钢筋的长度为 1
、2
和 3
,则可以将它们焊接在一起形成长度为 6
的支架。
返回 广告牌的最大可能安装高度 。如果没法安装广告牌,请返回 0
。
数据范围
0 <= rods.length <= 20
1 <= rods[i] <= 1000
sum(rods[i]) <= 5000
分析
令 d p [ i ] [ j ] dp[i][j] dp[i][j]为使用前 i i i个rod,差值为j的最大安装高度和,最后的结果即为 d p [ n ] [ 0 ] / 2 dp[n][0]/2 dp[n][0]/2
考虑四种情况
- 不使用第i根rod
- dp[i][j]=dp[i-1][j]
- 将第i根rod加入到短的那根,且加入后短的仍然短
- d p [ i ] [ j ] = d p [ i − 1 ] [ j + r o d [ i ] ] + r o d [ i ] dp[i][j]=dp[i-1][j + rod[i]] + rod[i] dp[i][j]=dp[i−1][j+rod[i]]+rod[i]
- 将第i根rod加入到短的那根,加入后短的变长
- d p [ i ] [ j ] = d p [ i − 1 ] [ r o d [ i ] − j ] + r o d [ i ] dp[i][j]=dp[i-1][rod[i]-j]+rod[i] dp[i][j]=dp[i−1][rod[i]−j]+rod[i]
- 将第i根rod加入到长的那根,加入后长的更长
- d p [ i ] [ j ] = d p [ i − 1 ] [ j − r o d [ i ] ] + r o d [ i ] dp[i][j]=dp[i-1][j-rod[i]]+rod[i] dp[i][j]=dp[i−1][j−rod[i]]+rod[i]
最后四种情况取 m a x max max
代码
class Solution {
public:const static int N = 5005, M = 25;int dp[M][N]; int tallestBillboard(vector<int>& rods) {int n = rods.size();memset(dp, -0x3f, sizeof(dp));dp[0][0] = 0;for(int i = 0; i < n; i ++ ) {for(int j = 0; j + rods[i] <= 5000; j ++ ) {dp[i + 1][j] = dp[i][j];dp[i + 1][j] = max(dp[i + 1][j], dp[i][abs(j - rods[i])] + rods[i]);dp[i + 1][j] = max(dp[i + 1][j], dp[i][j + rods[i]] + rods[i]);}}return dp[n][0] / 2;}
};
3082. 求出所有子序列的能量和
给你一个长度为 n
的整数数组 nums
和一个 正 整数 k
。
一个整数数组的 能量 定义为和 等于 k
的子序列的数目。
请你返回 nums
中所有子序列的 能量和 。
由于答案可能很大,请你将它对 109 + 7
取余 后返回。
数据范围
1 <= n <= 100
1 <= nums[i] <= 104
1 <= k <= 100
分析
令 d p [ i ] [ j ] dp[i][j] dp[i][j]为前i个能量为j的子序列数目和,我们考虑添加第的第i个数的性质
- 首先,加入第i个数,前面dp[i-1][j]个子序列若加入这第i个数子序列仍然成立,因此 d p [ i ] [ j ] = 2 ∗ d p [ i − 1 ] [ j ] dp[i][j]=2*dp[i-1][j] dp[i][j]=2∗dp[i−1][j](一个是前i-1个数原来有的子序列,另一个是加入第i个数构成的新的子序列中不选第i个数的能量和)
- 若第i个数正好为j,则他能和前面i个数构成的所有子序列构成新的子序列,且新的子序列只选他,此时新加入的能量为 2 i 2^i 2i(即前i个数构成的子序列个数)
- 否则 d p [ i ] [ j ] + = d p [ i − 1 ] [ j − n u m s [ i ] ] dp[i][j]+=dp[i-1][j-nums[i]] dp[i][j]+=dp[i−1][j−nums[i]]
代码
typedef long long LL;
class Solution {
public:const static int N = 105, mod = 1e9 + 7;LL dp[N][N]; // 前i个能量为j的子序列数目和LL qpow(LL a, LL n) {LL res = 1;while(n) {if(n & 1) res = res * a % mod;a = a * a % mod;n >>= 1;}return res;}LL sumOfPower(vector<int>& nums, int k) {int n = nums.size();dp[0][0] = 1;for(int i = 0; i < n; i ++ ) {for(int j = 0; j <= k; j ++ ) {dp[i + 1][j] += 2 * dp[i][j];if(nums[i] == j) {dp[i + 1][j] += qpow(2, i);} else {if(j >= nums[i]) {dp[i + 1][j] += dp[i][j - nums[i]];}}dp[i + 1][j] %= mod;}}return dp[n][k];}
};