P1133 教主的花园
题目链接
解题思路
显而易见是一道线性DP
我一开始想的是两维状态,即
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示考虑了前
i
i
i颗树,第
i
i
i棵树是第
j
j
j类的树(其中
j
∈
{
0
,
1
,
2
}
j\in\{0, 1, 2\}
j∈{0,1,2},分别表示高度为10, 20, 30的树)
但是,还有个东西没有考虑,那就是我们这第
i
i
i棵树是处于树高的波峰还是波谷呢?于是再加上:
f
[
i
]
[
j
]
[
0
/
1
]
f[i][j][0/1]
f[i][j][0/1]表示考虑了前
i
i
i颗树,第
i
i
i棵树是第
j
j
j类的树(其中
j
∈
{
0
,
1
,
2
}
j\in\{0, 1, 2\}
j∈{0,1,2},分别表示高度为10, 20, 30的树),且第
i
i
i棵树的树高是在相邻的两棵树的波峰(0)还是波谷(1)
另外,由于连成的是一个环,我们要特判1和n两个位置,跑三次dp就好了。
大致如此
详细代码
#define USEFASTREAD 0
#include<cstdio>
#define inl inline
#define rg register
#define Rep(i, s, t) for(rg int i = s; i <= t; i++)
#define Repd(i, t, s) for(rg int i = t; i >= s; i--)
#define putln putchar('\n')
#define putsp putchar(' ')
typedef long long ll;
#if USEFASTREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
void RS() {freopen("test.in", "r", stdin); freopen("test.out", "w", stdout);}
inl ll read() {
ll x = 0, f = 1; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
inl void write(ll x) {
if(x < 0) {x = -x; putchar('-');}
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
inl void writeln(ll x) {write(x); putln;}
inl void writesp(ll x) {write(x); putsp;}
}
using namespace IO;
template<typename T> inl T Max(const T& x, const T& y) {return x < y ? y : x;}
template<typename T> inl T Min(const T& x, const T& y) {return x < y ? x : y;}
template<typename T> inl void Swap(T& x, T& y) {T t = x; x = y; y = t;}
template<typename T> inl T Abs(const T& x) {return x < 0 ? -x : x;}
#include<cstring>
const int MAXN = 1e6 + 5;
int n;
ll f[MAXN][3][2]; //种到第i棵树,种类是j,是波峰(k = 0) 或 波谷(k = 1)
ll v[MAXN][3];
ll ans;
int main() {
n = read();
for(rg int i = 1; i <= n; i++)
v[i][0] = read(), v[i][1] = read(), v[i][2] = read();
for(rg int firj = 0; firj < 3; firj++) {//枚举第一颗种啥
memset(f, 0x00, sizeof f);
f[1][firj][0] = f[1][firj][1] = v[1][firj];
for(rg int i = 2; i <= n; i++)
for(rg int j = 0; j < 3; j++) {
ll &f0 = f[i][j][0], &f1 = f[i][j][1];
ll &nv = v[i][j];
for(rg int lj = 0; lj < j; lj++) {//上一次种的是波谷(k = 1),这一次种的是波峰(k = 0)
f0 = Max(f0, f[i - 1][lj][1] + nv);
}
for(rg int lj = j + 1; lj < 3; lj++) {
f1 = Max(f1, f[i - 1][lj][0] + nv);
}
}
for(rg int j = 0; j < firj; j++) //1是波峰(k = 0),现在是波谷(k = 1)
ans = Max(ans, f[n][j][1]);
for(rg int j = firj + 1; j < 3; j++)
ans = Max(ans, f[n][j][0]);
}
write(ans);
return 0;
}
P1279 字串距离
题目链接
解题思路
我们易设状态为
f
[
i
]
[
j
]
f[i][j]
f[i][j]匹配A串前
i
i
i个字符和B串前
j
j
j个字符所得到的距离。
那么易得转移方程:
f
[
i
]
[
j
]
=
m
a
x
{
f
[
i
−
1
]
[
j
]
+
K
−
−
−
−
−
−
−
i
f
A
[
i
]
放
空
格
f
[
i
]
[
j
−
1
]
+
K
−
−
−
−
−
−
−
i
f
B
[
i
]
放
空
格
f
[
i
−
1
]
[
j
−
1
]
+
a
b
s
(
A
[
i
]
−
B
[
i
]
)
−
−
直
接
匹
配
f[i][j]=max\left\{\begin{matrix} f[i-1][j] + K-------if\ A[i]放空格\\ f[i][j-1]+K-------if\ B[i]放空格\\ f[i-1][j-1]+abs(A[i]-B[i])--直接匹配 \end{matrix}\right.
f[i][j]=max⎩⎨⎧f[i−1][j]+K−−−−−−−if A[i]放空格f[i][j−1]+K−−−−−−−if B[i]放空格f[i−1][j−1]+abs(A[i]−B[i])−−直接匹配
注意边界!
详细代码
#define USEFASTERREAD 0
#define rg register
#define inl inline
#define DEBUG printf("qwq\n")
#define DEBUGd(x) printf("var %s is %lld", #x, ll(x))
#define DEBUGf(x) printf("var %s is %llf", #x, double(x))
#define putln putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
typedef unsigned long long ull;
#include<cstdio>
#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
inl void RS() {freopen("test.in", "r", stdin), freopen("test.out", "w", stdout);}
inl ll read() {
ll x = 0, f = 1; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
return x * f;
}
inl void write(ll x) {
if(x < 0) {putchar('-'); x = -x;}
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
inl void writeln(ll x) {write(x), putln;}
inl void writesp(ll x) {write(x), putsp;}
}
using namespace IO;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
template<typename T> inline T Abs(const T& x) {return x < 0 ? -x : x;}
#include<cstring>
const int MAXLEN = 2005;
const int INF = 0x3f3f3f3f;
char A[MAXLEN], B[MAXLEN];
int n, m;
int K;
int f[MAXLEN][MAXLEN];
int main() {
//RS();
scanf("%s", A + 1);
scanf("%s", B + 1);
K = read();
n = strlen(A + 1); m = strlen(B + 1);
memset(f, 0x3f, sizeof f);
f[0][0] = 0;
for(rg int i = 1; i <= n; i++) f[i][0] = i * K;
for(rg int i = 1; i <= m; i++) f[0][i] = i * K;
for(rg int i = 1; i <= n; i++)
for(rg int j = 1; j <= m; j++) {
f[i][j] = Min(f[i][j], f[i - 1][j] + K);
f[i][j] = Min(f[i][j], f[i][j - 1] + K);
f[i][j] = Min(f[i][j], f[i - 1][j - 1] + Abs(A[i] - B[j]));
}
writeln(f[n][m]);
return 0;
}