小清新DP题(多做多想)

2024-04-23 10:20
文章标签 dp 清新

本文主要是介绍小清新DP题(多做多想),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

牛客小白月赛90 F

  • problem
    在这里插入图片描述
  • solution
    在这里插入图片描述
 	R(n), R(m); int L = 0;F(i, 1, m) R(d[i].st), R(d[i].en), c[++ L] = d[i].st, c[++ L] = d[i].en;c[++ L] = n;sort(c + 1, c + L + 1); int cnt = 0;F(i, 1, L) if (c[i] != c[i - 1]) {g[c[i]] = ++ cnt;D[cnt] = c[i];}sort(d + 1, d + m + 1);f[0][0][0] = 1;F(i, 0, m - 1)F(j, 0, cnt)F(k, 0, cnt) if (f[i][j][k]) {add(f[i + 1][j][k], f[i][j][k]);int l = D[j], r = D[k];int l_ = g[d[i + 1].st], r_ = g[d[i + 1].en];if (d[i + 1].st - 1 <= l) {add(f[i + 1][max(j, min(k, r_))][max(k, r_)], f[i][j][k]);}}W(f[m][cnt][cnt]);




CF833B The Bakery

  • 线段树优化DP
    在这里插入图片描述





  • 6353. 【NOIP2019模拟】给(ca)

  • Problem

在这里插入图片描述

这题题目需要注意就是每个节点都应该有2个儿子(他说没有叶子结点是错的,应该是要么没有儿子,要么有两个儿子),然后要求是到达每个叶子结点需要经过的向左的边不能超过M条.

  • Solution

    容易想到简单的计数Dp,f[i][j]表示当前有i个叶节点,最多的向左走了M次,O(n^3)

    非常妙的优化是考虑从dfs序角度DP,因为每一棵树都唯一对应着一个DFS序

    在这里插入图片描述
    在这里插入图片描述

S 老师的合并

  • problem
    在这里插入图片描述
  • solution

在这里插入图片描述

在合并括号序列时,先关注当前最后一个括号所配对到的位置,考虑求这一部分的方案数,再考虑剩下的部分方案(可以再递归去求方案)。

只能说不看这代码根本不知道这题解想要表达什么,具体想法参见代码,真的非常妙

void DFS(int u, int dep, vector<int> *G, vector<int> *tt, int *ttt) {tt[dep].push_back(u);ttt[u] = tt[dep].size() - 1;for (int v: G[u])DFS(v, dep + 1, G, tt, ttt);return;
}int ct = 0;int Solve(int nw1, int nw2, int lp1, int rp1, int lp2, int rp2) {if (lp1 == -1 || lp2 == -1)return 1;if (lp1 > rp1 || lp2 > rp2)return 1;int l1 = bin1[nw1][lp1], r1 = bin1[nw1][rp1]; // bin1[nw1][x] 表示第一棵树第nw1层的第x个节点int l2 = bin2[nw2][lp2], r2 = bin2[nw2][rp2]; // bin2[nw2][x] 表示第二棵树第nw2层的第x个节点if (vis[l1][r1][l2][r2])return dp[l1][r1][l2][r2];LL res = 0;++ ct;Add(res, Solve(nw1, nw2, lp1, rp1 - 1, lp2, rp2)); // 当前序列后面没有括号要合并了,第一课树的第rp1对应节点作为最外层括号。Add(res, Solve(nw1, nw2, lp1, rp1, lp2, rp2 - 1));
// 下面表示要合并括号的。int ll = 0, rr = 0;if (G2[r2].size())ll = id2[G2[r2][0]], rr = id2[G2[r2].back()];else ll = rr = -1;for (int i = 1; i <= rp1 - lp1 + 1; i++)Add(res, 1ll * Solve(nw1, nw2, lp1, rp1 - i, lp2, rp2 - 1) * Solve(nw1, nw2 + 1,rp1 - i + 1, rp1, ll, rr) % mod); // 表示当前最后一个括号是第二棵树的, rp1-i就表示用第一棵树当前深度的后面i个作为后缀,if (G1[r1].size())ll = id1[G1[r1][0]], rr = id1[G1[r1].back()];else ll = rr = -1;for (int i = 1; i <= rp2 - lp2 + 1; i++)Add(res, 1ll * Solve(nw1, nw2, lp1, rp1 - 1, lp2, rp2 - i) * Solve(nw1 + 1, nw2,ll, rr, rp2 - i + 1, rp2) % mod);vis[l1][r1][l2][r2] = 1;dp[l1][r1][l2][r2] = res;return res;
}int main() {n1 = read();for (int i = 2; i <= n1; i++)G1[read()].push_back(i);n2 = read();for (int i = 2; i <= n2; i++)G2[read()].push_back(i);DFS(1, 0, G1, bin1, id1);DFS(1, 0, G2, bin2, id2);LL ans = 0;if (G1[1].size()) {Add(ans, Solve(1, 0, id1[G1[1][0]], id1[G1[1].back()], 0, 0)); // 最外层括号是第一棵树的根节点} else Add(ans, 1); // 否则第二棵树的括号序只能不变的放到最外括号的里边if (G2[1].size()) {Add(ans, Solve(0, 1, 0, 0, id2[G2[1][0]], id2[G2[1].back()])); // 同理,最外层括号是第二棵树的根节点} else Add(ans, 1);cout << ans;


J. Journey on the Number Line

Problem

在这里插入图片描述

Solution

在这里插入图片描述

这里的实现参考:

for(int i=1;i<=n;i++) {for(int j=1;j<=i;j++)if(id[i]==1||id[i]==n) {trans(dp[i][j],dp[i-1][j-1],-x[id[i]]-y[id[i]],1);if(j)trans(dp[i][j],dp[i-1][j],x[id[i]]+y[id[i]],1);// 这里有点运用插空法的思想,头和尾的位置是固定的,所以方案乘1,其余是有几个空格就有乘多少方案,这样算起来容易太多了}else {if (j - tot > 0)trans(dp[i][j],dp[i-1][j-1],-2*x[id[i]]-2*y[id[i]],j-tot); // 这里就是j-1个联通块,有j个空,减去tot个(头尾影响),这里相当于作为一个独立的联通块加进去if (2 * j - tot > 0)trans(dp[i][j],dp[i-1][j],0,2*j-tot); // 这里是和之前的联通块合并,之前每个联通块都有头和尾,这个可以放到头或尾,同理要减去tot(不能放到st的头/en的尾)trans(dp[i][j],dp[i-1][j+1],2*x[id[i]]+2*y[id[i]],j); // 这里是合并两个联通块,j+1个联通块,当然只能有j个地方可以连,这是因为这些联通块的顺序已经相对确定了。}tot+=(id[i]==1||id[i]==n);
}

这篇关于小清新DP题(多做多想)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/928524

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

XTU 1233 n个硬币连续m个正面个数(dp)

题面: Coins Problem Description: Duoxida buys a bottle of MaiDong from a vending machine and the machine give her n coins back. She places them in a line randomly showing head face or tail face o

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int