AtCoder Educational DP Contest

2024-04-17 00:44
文章标签 dp atcoder contest educational

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

A - Frog 1

大意

n块石头,第i块石头的高度为h_i。从石头i跳到石头j的花费是|h_i-h_j|

一只青蛙在石头1上,每次可以跳1步或2步,请问跳到石头n的最小代价是多少?

2 \le n \le 10^5, 1 \le h_i \le 10^4

思路

\operatorname{cost}(i,j)=|h_i-h_j|dp_i为青蛙跳到第i号石头时的最小代价。

每一个点都可以由前两个点转移而来,因此状态转移方程为:

dp_i=\min(dp_{i-1}+\operatorname{cost}(i-1,i), dp_{i-2}+\operatorname{cost}(i-2, i))

边界可由定义得出:dp_1=0,dp_2=\operatorname{cost}(1,2)

时间复杂度O(n)

代码

#include <iostream>
#include <vector>
using namespace std;
#define int long long
signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n;cin >> n;vector<int> a(n + 1), dp(n + 1, 0);for(int i = 1; i <= n; i++) cin >> a[i];auto cost = [&](int i, int j) -> int{int ret = a[i] - a[j];if(ret < 0) ret = -ret;return ret;};dp[2] = cost(1, 2);for(int i = 3; i <= n; i++)dp[i] = min(dp[i - 1] + cost(i, i - 1), dp[i - 2] + cost(i, i - 2));cout << dp[n] << endl;return 0;
}

B - Frog 2

大意

n块石头,第i块石头的高度为h_i。从石头i跳到石头j的花费是|h_i-h_j|

一只青蛙在石头1上,每次可以跳1~k步,请问跳到石头n的最小代价是多少?

2 \le n \le 10^5, 1 \le k \le 100, 1 \le h_i \le 10^4

思路

和上一题一样,设\operatorname{cost}(i,j)=|h_i-h_j|dp_i为青蛙跳到第i号石头时的最小代价。

每一个点都可以由前k个点转移而来(除了i < k的情况),因此状态转移方程为:

dp_i=\min(dp_{i-1}+\operatorname{cost}(i-1,i), dp_{i-2}+\operatorname{cost}(i-2, i), \cdots, dp_{\max(1, i - k)} + \operatorname{cost}(\max(1, i - k), i))

边界为dp_1=0

时间复杂度O(nk)

代码

#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, k;cin >> n >> k;vector<int> a(n + 1), dp(n + 1, INF);for(int i = 1; i <= n; i++) cin >> a[i];auto cost = [&](int i, int j){int ret = a[i] - a[j];return (ret > 0? ret: -ret);};dp[1] = 0;for(int i = 2; i <= n; i++){for(int j = max(1ll, i - k); j < i; j++) dp[i] = min(dp[i], dp[j] + cost(i, j));}cout << dp[n] << endl;
}

C - Vacation

大意

n天时间和3种活动。每天只能进行一个活动,且相邻两天不能做相同的活动。

i天做三种活动分别可以获得a_i,b_i,c_i点快乐值,求这n天里最大可以获得多少点快乐值。

1 \le n \le 10^5, 1 \le a_i,b_i,c_i \le 10^4

思路

dp_{i,j}为考虑到第i天,且第i天进行活动j的最大值。

由于相邻两天不能做相同的活动,所以dp_{i,j}只能从另外两个状态中的最大值转移过来。、

因此,状态转移方程为:

\begin{cases} dp_{i,1}=\max(dp_{i-1,2}, dp_{i-1,3}) + a_i \\ dp_{i,2}=\max(dp_{i-1,1}, dp_{i-1,3}) + b_i \\ dp_{i,3}=\max(dp_{i-1,1}, dp_{i-1,2}) + c_i \end{cases}

边界为dp_{0,1}=dp_{0,2}=dp_{0,3}=0,答案为\max(dp_{n,1}, dp_{n,2}, dp_{n,3})

时间复杂度O(n)

代码

#include <iostream>
#include <vector>
using namespace std;
#define int long longsigned main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n;cin >> n;vector<int> a(n + 1), b(n + 1), c(n + 1);vector<int> dp1(n + 1, 0), dp2(n + 1, 0), dp3(n + 1, 0);for(int i = 1; i <= n; i++) cin >> a[i] >> b[i] >> c[i];for(int i = 1; i <= n; i++){dp1[i] = max(dp2[i - 1], dp3[i - 1]) + a[i];dp2[i] = max(dp1[i - 1], dp3[i - 1]) + b[i];dp3[i] = max(dp1[i - 1], dp2[i - 1]) + c[i];}cout << max(dp1[n], max(dp2[n], dp3[n])) << endl;
}

D - Knapsack 1

大意

n件物品和一个承重量为m千克的袋子。

i件物品的重量为w_i千克,价值为v_i元。

现在要挑选一些物品装入袋子里,求选择的物品的最大总价值。

1 \le n\le 100, 1 \le m \le 10^5, 1 \le w_i \le m, 1 \le v_i \le 10^9

思路

经典01背包问题,按照01背包的解法做即可。

注意需要long long。

时间复杂度O(nm)

代码

#include <iostream>
#include <vector>
using namespace std;
#define int long longsigned main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, m;cin >> n >> m;vector<int> w(n + 1), v(n + 1), dp(m + 1, 0);for(int i = 1; i <= n; i++) cin >> w[i] >> v[i];for(int i = 1; i <= n; i++)for(int j = m; j >= w[i]; j--)dp[j] = max(dp[j], dp[j - w[i]] + v[i]);cout << dp[m] << endl;return 0;
}

E - Knapsack 2

大意

n件物品和一个承重量为m千克的袋子。

i件物品的重量为w_i千克,价值为v_i元。

现在要挑选一些物品装入袋子里,求选择的物品的最大总价值。

1 \le n\le 100, 1 \le m \le 10^9, 1 \le w_i \le m, 1 \le v_i \le 10^3

思路

w_i很大,直接套用01背包计算,时间和空间肯定一定炸。

由于v_i很小,我们可以转换思路,设dp_{j}为价值为j 的最小重量,这样就不会炸了。

最后从大到小遍历j,找到符合dp_j \le m的直接输出j

时间复杂度O(ns),其中sj的取值范围,s=\sum v_i

代码

#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, m;cin >> n >> m;vector<int> w(n + 1), v(n + 1);int sum = 0;for(int i = 1; i <= n; i++){cin >> w[i] >> v[i];sum += v[i];}vector<int> dp(sum + 1, INF);dp[0] = 0;for(int i = 1; i <= n; i++)for(int j = sum; j >= v[i]; j--)dp[j] = min(dp[j], dp[j - v[i]] + w[i]);for(int j = sum; j >= 0; j--)if(dp[j] <= m){cout << j << endl;break;}return 0;
}

F - LCS

题意

给定两个字符串,输出它们的任意一个最长公共子序列。

思路

求LCS时将最优策略保存下来,用x_{i,j}来表示状态(i,j)是否和(i-1,j)有关,y_{i,j}来表示状态(i,j)是否和(i,j-1)有关。

根据xy,就可以递归输出方案。

代码

#include <iostream>
#include <vector>
using namespace std;
int main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);string x, y;cin >> x >> y;int n = x.size(), m = y.size();vector<vector<int>> dp(n + 1, vector<int>(m + 1));vector<vector<int>> f1(n + 1, vector<int>(m + 1));vector<vector<int>> f2(n + 1, vector<int>(m + 1));auto lcs = [&](string a, string b, int n, int m) -> void{for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){if(a[i - 1] == b[j - 1]){dp[i][j] = dp[i - 1][j - 1] + 1;f1[i][j] = 1;f2[i][j] = 1;}else if(dp[i - 1][j] > dp[i][j - 1]){dp[i][j] = dp[i - 1][j];f1[i][j] = 1;}else{dp[i][j] = dp[i][j - 1];f2[i][j] = 1;}}};string ans = "";auto dfs = [&](auto self, string a, string b, int i, int j) -> void{if(i == 0 || j == 0) return;self(self, a, b, i - f1[i][j], j - f2[i][j]);if(a[i - 1] == b[j - 1]) ans.push_back(a[i - 1]);};lcs(x, y, n, m);dfs(dfs, x, y, n, m);cout << ans << endl;}

这篇关于AtCoder Educational DP Contest的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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