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]
代码没有。。。