力扣10.31

956. 最高的广告牌

你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。

你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋的长度为 123,则可以将它们焊接在一起形成长度为 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[i1][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[i1][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[i1][jrod[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]=2dp[i1][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[i1][jnums[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];
    }   
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值