DP做题记

P3146 [USACO16OPEN] 248 G

我们可以想到用区间DP来做

fl,r 表示 [l,r] 的区间内其中合并能获得的最大分值

我们要枚举区间断点 k ,然后我们来看一下在如何的情况下我们可以转移

  1. fl,k=fk+1,r 因为想要合并左右区间两边必须相等

  2. fl,k0 因为两个不存在的东西不能合并

状态转移方程

fl,r=max(fl,r,fk+1,r+1)

#include <bits/stdc++.h> using namespace std; const int N = 1e3 + 10; int dp[N][N], n, a[N], ans = 0; inline int read() { int x = 0, f = 1; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -f; s = getchar(); } while (s >= '0' && s <= '9') { x = (x << 3) + (x << 1) + (s ^ 48); s = getchar(); } return x * f; } int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; ans = max(ans, a[i]); dp[i][i] = a[i]; } for (int len = 2; len <= n; len++) { for (int l = 1; l + len - 1 <= n; l++) { int r = l + len - 1; for (int k = l; k < r; k++) { if (dp[l][k] == dp[k + 1][r] && dp[l][k]) { dp[l][r] = max(dp[l][r], dp[l][k] + 1); ans = max(ans, dp[l][r]); } } } } cout << ans << endl; return 0; }

P4084 [USACO17DEC] Barn Painting G

fi,13 表示选 i 且第 i 个上色为 j 的所有方案数

对于所有的初始节点 fi,1=fi,2=fi,3=1 因为放一个数算一种方案

然后当某个节点被指定上色,其余另两位颜色的方案数为 0

例如:如果被指定上色为 1 fi,2=fi,3=0

对于每个子节点来说,都不可以与父节点相同

#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 7, M = N * 2, MOD = 1e9 + 7; typedef long long LL; int n, k, ans; int h[M], ne[M], e[M], f[M][4], idx; // w代表可能性 int add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } void dfs(int u, int fa) { for (int i = 1; i <= 3; i++) { if (f[u][i]) { for (int j = 1; j <= i; j++) f[u][j] = 0; } f[u][i] = 1; } for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (j != fa) { dfs(j, u); //因为父节点和子节点所用的颜色不能相同,乘法原理 f[u][1] = f[u][1] * (f[j][2] + f[j][3] % MOD) % MOD; f[u][2] = f[u][2] * (f[j][1] + f[j][3] % MOD) % MOD; f[u][3] = f[u][3] * (f[j][1] + f[j][2] % MOD) % MOD; } } } int main() { memset(h, -1, sizeof(h)); cin >> n >> k; for (int i = 1; i < n; i++) { int a, b; cin >> a >> b; add(a, b), add(b, a); } for (int i = 1; i <= k; i++) { int a, k; cin >> a >> k; f[a][k] = 1; } dfs(1, 0); cout << (f[1][1] + f[1][2] + f[1][3]) % MOD;//因为我们先递归后计算 //所以算到f[1][...]时已是最后计算的 return 0; }

P8801 [蓝桥杯 2022 国 B] 最大数字

这道题我们可以想到贪心的思想

如果能成为 9 就尽量成为 9 ,如果不能成为的话就尽量将数字变大

所以我们有 4 种情况

  1. 如果两种操作都可以变成 9 ,那么两种都试试

  2. 如果只有第一种操作能变成 9 ,那么就用第一种

  3. 如果只有第二种操作能变成 9 ,那么就用第二种

  4. 如果不行,就用光第一次操作,将这一位变得尽量大

因为是暴力搜索每一个数位,设位数为 x ,时间复杂度为 2x

#include <bits/stdc++.h> using namespace std; string s, ans; int n, a, b; //第k位,atim表示用了几次1操作,btim表示用了几次2操作,now表示目前的字符串 void dfs(int k, int atim, int btim, string now) { if (k == n) { if (now > ans) //选择最优解 ans = now; return; } int x = 9 - (now[k] - '0'), y = now[k] - '0' + 1; // x和y表示几次能变成9 if (atim + x <= a && btim + y <= b) //如果两个都能变成9 { //两个都试一试 now[k] = '9'; dfs(k + 1, atim + x, btim, now); dfs(k + 1, atim, btim + y, now); } else if (atim + x <= a) //如果操作1能变成9 { now[k] = '9'; dfs(k + 1, atim + x, btim, now); } else if (btim + y <= b) //如果操作2能变成9 { now[k] = '9'; dfs(k + 1, atim, btim + y, now); } else //如果都不能 { //把操作1用完 now[k] += a - atim; dfs(k + 1, a, btim, now); } } int main() { cin >> s >> a >> b; n = s.size(); dfs(0, 0, 0, s); cout << ans << endl; return 0; }

__EOF__

本文作者ljfyyds
本文链接https://www.cnblogs.com/ljfyyds/p/17526019.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   ljfyyds  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示