dp专题一

2 篇文章 0 订阅

dp专题一

1.数塔
dp[i][j] = max(dp[i-1][j] + dp[i-1][j-1]) + a[i][j]
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

int a[200][200];
int f[200][200] = { 0 };

int max(int a, int b) {
    return a > b ? a : b;
}

int dp(int i, int j) {
    if (f[i][j])
        return f[i][j];
    else if (a[i][j] < 0) {
        return 0;
    }
    else if (i == 1) {
        f[i][j] = a[i][j];
        return f[i][j];
    }
    else {
        f[i][j] = max(dp(i - 1, j), dp(i - 1, j - 1)) + a[i][j];
    }
    return f[i][j];
}

int main()
{
    int T;
    cin >> T;
    while (T--) {
        int maxx = 0;
        int n;
        cin >> n;
        memset(a, -1, sizeof(a));
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++) 
            for (int j = 1; j <= i; j++) {
                scanf("%d", &a[i][j]);
            }
        for (int i = 1; i <= n; i++) {
            maxx = max(maxx, dp(n, i));
        }
        cout << maxx << endl;
    }
}
2.最大连续子序列

​ 惭愧,这题一开始居然没有思路

​ 这种题目一定是要用f[i]作为状态来记录f[i]作为最后一个的最大连续子序列,自然而然有一个简单的数学道理:如果最大的到这里是负数,那么下一个一定可以另起炉灶。其实不要这个数学推理这题也出来了,下一题看一下和这一题很像的一道

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

typedef struct {
    int l, v;
} num;

int a[20000] = { 0 };
num f[20000] = { 0 };

int max(int a, int b) {
    return a > b ? a : b;
}

int main()
{
    int n;
    cin >> n;
    while (n) {
        int maxx = -1;
        for (int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        for (int i = 0; i < n; i++) {
            if (f[i - 1].v <= 0) {
                f[i].l = i;
                f[i].v = a[i];
            }
            else {
                f[i] = f[i - 1];
                f[i].v += a[i];
            }
        }
        int lt = 0, rt = n-1;
        for (int i = 0; i < n; i++) {
            if (f[i].v > maxx) {
                maxx = f[i].v;
                lt = f[i].l;
                rt = i;
            }
        }
        if (maxx < 0)
            maxx = 0;
        printf("%d %d %d\n", maxx, a[lt], a[rt]);
        cin >> n;
    }
}
3.Xieldy And His Password

​ 这题用脚想都应该知道是dp,现场还觉得可能会有数学规律,结果打了个表并没有发现数学规律。。。

​ 这题状态肯定是f[i]代表以i为结尾的子串,在十进制下表示为3k的方案数,但是怎么转移呢?现场在想向后转移,想往后找能不能找到一种规律,使得例如找个‘11’或‘0’就转移,结果发现这个方法是不成立的。

​ 那么换过来想想,众所周知,dp必须要有一个初始状态,那什么才是初始状态呢?难不成非要从头开始找,找到3k才能算是初始状态吗?能不能把自己作为一个初始状态呢?一般dp不都是这么搞的吗?那如果我把每一个数都当成一个状态,但是我一个数只能是0或1反正肯定不会是3,这咋整?

​ 那不然把状态定为“膜3的值”?

f[i][j] 定义为 以i为结尾,膜3等于j的方案数
f[i][(j * 2 + a[i]) % 3] = f[i - 1][j];
f[i][a[i]] += 1;
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>

using namespace std;

#define MAX 2000000
#define ll long long

int a[MAX] = { 0 };
ll f[MAX][3] = { 0 };

int main()
{
    string s;
    while (cin >> s) {
        memset(f, 0, sizeof(f));
        for (int i = 0; s[i]; i++) {
            a[i] = s[i] - '0';
        }
        f[0][a[0]] = 1;
        for (int i = 1; i < s.size(); i++) {
            for (int j = 0; j < 3; j++) {
                f[i][(j * 2 + a[i]) % 3] = f[i - 1][j];
            }
            f[i][a[i]] += 1;
        }
        ll sum = 0;
        for (int i = 0; i < s.size(); i++) {
            sum += f[i][0];
        }
        cout << sum << endl;
    }
}
4.免费馅饼
f[i][j] = max(f[i-1][j-1], f[i][j-1], f[i+1][j]) + a[i][j]

代码没有。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值