dp

LeetCode.10.正则表达式匹配

≡放荡痞女 提交于 2020-02-27 01:03:07
这个比较困难,我参考了网上的代码: https://leetcode-cn.com/problems/regular-expression-matching/solution/di-gui-dong-tai-gui-hua-zhu-xing-jie-shi-python3-b/ 思路: 动态规划, 沿着匹配串和字符串构成矩阵的对角线传递状态 1. 状态矩阵的首行与首列对应于空字符与空匹配符 2. 对角线意味着匹配串是否匹配对应的字符串 具体代码以下: ''' p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1] If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1]; If p.charAt(j) == '*': here are two sub conditions: //in this case, a* only counts as empty, otherwise is not match - if p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] - if p.charAt(j-1) == s.charAt(i) or p.charAt(i-1) == '.': dp[i][j] = dp[i-1][j] //in this

LeetCode--10. 正则表达式匹配(java)

纵饮孤独 提交于 2020-02-26 03:07:05
推荐题解 大佬的优质题解,收藏学习 class Solution { public boolean isMatch ( String s , String p ) { if ( s == null || p == null ) return false ; int m = s . length ( ) , n = p . length ( ) ; boolean [ ] [ ] dp = new boolean [ m + 1 ] [ n + 1 ] ; dp [ 0 ] [ 0 ] = true ; //"" 和p的匹配关系初始化,a*a*a*a*a*这种能够匹配空串,其他的是都是false。 // 奇数位不管什么字符都是false,偶数位为* 时则: dp[0][i] = dp[0][i - 2] for ( int i = 2 ; i <= n ; i += 2 ) { if ( p . charAt ( i - 1 ) == '*' ) { dp [ 0 ] [ i ] = dp [ 0 ] [ i - 2 ] ; } } for ( int i = 1 ; i <= m ; i ++ ) { for ( int j = 1 ; j <= n ; j ++ ) { char sc = s . charAt ( i - 1 ) ; char pc = p . charAt (

【cf1315E】E. Double Elimination(dp)

南笙酒味 提交于 2020-02-25 22:14:35
传送门 题意: 现有 \(2^n,n\leq 17\) 个参赛选手,开始 \(2\cdot i,2\cdot i-1\) 两两配对进行比赛。 比赛规则:每场比赛中赢的人会进入胜者组,输的人会进入败者组,一个人如果输两次那么直接出局。最终胜者组和败者组最终会只剩下一个人,决赛时只进行一场,赢的人就胜利。 现在你有 \(k\) 支心仪的队伍,你能够安排每场比赛的胜负,你希望看到尽量多的比赛中含有你的心仪队伍。 问这样的比赛数量最多为多少。 可以结合下图理解一下: 思路: 这个题初看不是很好思考,直接看了题解...接下来说说大概思路: 因为共有 \(2^n\) 个人,结合题意可以考虑合并两个 \(2^{i-1}\) 到 \(2^i\) 。 如果想到了 \(dp\) ,那么问题就转化为怎么定义 \(dp\) 状态和进行状态的合并。 最显然的想法就是 \(dp_{i,j,k}\) 表示长度为 \(2^i\) ,起点为 \(j\) ,最终剩下的队伍是否为心仪的队伍。但是这种状态的定义不能考虑到输掉一场的人。因为两段合并时,不仅有赢的跟赢的打,还有输的跟输的打,最终再打一场才能决定最后的那个人。 因为上面的状态不能考虑到输的人,所以我们重新定义: \(dp_{i,j,f_1,f_2}\) 表示长度为 \(2^i\) ,起点为 \(j\) ,胜者组最后的队伍是否为心仪队伍

Java实现 LeetCode 132 分割回文串 II(二)

谁说胖子不能爱 提交于 2020-02-21 22:52:54
132. 分割回文串 II 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。 返回符合要求的最少分割次数。 示例: 输入: “aab” 输出: 1 解释: 进行一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。 class Solution { public int minCut(String s) { if(s == null || s.length() <= 1) return 0; int len = s.length(); int dp[] = new int[len]; Arrays.fill(dp, len-1); for(int i = 0; i < len; i++){ // 注意偶数长度与奇数长度回文串的特点 mincutHelper(s , i , i , dp); // 奇数回文串以1个字符为中心 mincutHelper(s, i , i+1 , dp); // 偶数回文串以2个字符为中心 } return dp[len-1]; } private void mincutHelper(String s, int i, int j, int[] dp){ int len = s.length(); while(i >= 0 && j < len && s.charAt(i) == s.charAt(j)){ dp[j] =

洛谷P4360[CEOI2004]锯木厂选址

孤街浪徒 提交于 2020-02-21 22:39:41
https://www.luogu.com.cn/problem/P4360 做两遍dp,dp[k][i]表示前i个位置放k个锯木厂的最小值 先把整个顺序反过来,那么0的位置就是山脚的锯木厂 设sum[i],f[i]是sum[i]w[i]前缀和,f2[i]是w[i]的前缀和 dp[1][i]=f[i]-f[k]-sum[k+1](f2[i]-f2[k])+dp[0][k] 展开成f2[k]sum[k+1]-f[k]+dp[0][k]=f2[i]sum[k+1]+dp[1][i]-f[i] k=f2[i]递增,sum[k+1]递增,希望截距dp[1][i]-f[i]尽可能小 画图分析得用单调队列维护一个下凸包 #include<bits/stdc++.h> using namespace std; const int maxl=2e4+10; typedef long long ll; int n; ll w[maxl],d[maxl],sum[maxl],f[maxl],f2[maxl]; ll dp[3][maxl]; struct node { ll x,y; }s[maxl]; inline void prework() { scanf("%d",&n); for(int i=n;i>=1;i--) scanf("%lld%lld",&w[i],&d[i]); for(int

ZOJ3537 Cake(区间dp+凸包判断)

为君一笑 提交于 2020-02-20 13:30:13
网上很多区间dp的代码是记忆化搜索的,还有些说这种区间dp必须倒序枚举 其实没有必要倒序,我们只需要按正常的区间dp的定义,第一维是长度,第二维枚举起点,第三维枚举断点即可 判断凸包的方法就是跟网上一样的常用方法Graham #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1005; const int inf = 1000000000; struct node { int x, y; } p[maxn], save[maxn], tmp[maxn]; int cost[maxn][maxn], n, m; int dp[maxn][maxn]; int dis(node p1, node p2, node p0) { return (p1.x-p0.x) * (p2.y-p0.y) - (p2.x-p0.x) * (p1.y-p0.y); } bool cmp(const node &a, const node &b) { if (a.y == b.y) return a.x < b.x; return a.y < b.y; } int Graham(node *p

ABC155E - Payment

懵懂的女人 提交于 2020-02-17 21:52:33
简述题意,给你一个大数,你可以选择10的次幂进行加减运算,问如何用最少的次数从0到达这个大数 考虑从这个大数到0,从最低位开始,每次都将这个位置取完,2种策略,贪心的话不好处理进位的情况,可以想到是DP 设dp[i][0]为取到第i位,将第i位直接拿完的最小次数,dp[i][1]为取到第i位,进位后拿完的最小次数,可以得到状态转移,num表示第i位的数字 dp[i][0] = min(dp[i-1][0], dp[i-1][1]+1) + num,dp[i-1][1]-1表示进了一位,所以第i位就要+1 dp[i][1] = 10 - num + min(dp[i-1][0], dp[i-1][1]-1) 同理,dp[i-1][1]进了一位,num相当于(num+1), 10-(num+1) = 10 - num - 1 注意初始化状态,最终取答案的时候要在最高位的下一位统计,因为最高位可能也进位了,相当于放了一个虚0 #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x)&(-x)) typedef long long LL; const int maxm = 1e6+5; int dp[maxm][2]; void run_case() { string str; cin >> str; dp

Java实现 LeetCode 64 最小路径和

耗尽温柔 提交于 2020-02-16 19:34:47
64. 最小路径和 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小。 class Solution { public int minPathSum(int[][] grid) { if (grid == null || grid.length < 1 || grid[0] == null || grid[0].length < 1) { return 0; } int row = grid.length; int col = grid[row - 1].length; int dp[][] = new int[row][col]; dp[0][0] = grid[0][0]; for (int i = 1;i < row;i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } for (int i = 1;i < col;i++) { dp[0][i] = dp[0][i - 1] + grid[0][i]; } for (int i = 1;i < row;i++) { for (int j = 1;j <

Educational Codeforces Round 82 (Rated for Div. 2) - E. Erase Subsequences 一个字符串是否可以拆分成两个序列

五迷三道 提交于 2020-02-15 06:23:55
题目链接:http://codeforces.com/contest/1303/problem/E 题目大意: 给你一个字符串S和一个字符串T。问能不能在S中找到一个子序列S1,然后从S中删除S1.再去删除后的字符串T中再找一个子序列S2。然后用S1+S2拼接成T。 思路:我们枚举T的分割点。进行dp。dp[i][j]:表示前i个字符和t1匹配到第j个字符时。能和t2匹配的最大长度。如果dp[|s|][|t1|]==|t2|就可行。注意t1和t2可能一个为空。特判就可以了。 # include <bits/stdc++.h> # define LL long long using namespace std ; int dp [ 500 ] [ 500 ] ; int check ( char s [ ] , char t1 [ ] , char t2 [ ] ) { memset ( dp , - 1 , sizeof ( dp ) ) ; int n = strlen ( s + 1 ) , n1 = strlen ( t1 + 1 ) , n2 = strlen ( t2 + 1 ) ; dp [ 0 ] [ 0 ] = 0 ; for ( int i = 1 ; i <= n ; i ++ ) { dp [ i ] [ 0 ] = 0 ; for ( int j = 0 ;

碎碎念(dp)

纵然是瞬间 提交于 2020-02-14 00:39:20
题目 链接:https://ac.nowcoder.com/acm/contest/3006/F 来源:牛客网 在ACM比赛里,除了CE以外都是有效的提交。每一个提交都会有其评测的结果,或是AC,或是RJ(Rejected,包含各种不通过的情况)。往往一个人上去提交的时候,总有一个队友会坐在边上等着结果。那个人,往往都是只读题不写题的云选手~ 牛牛战队里也有这样的云选手——牛能。当牛能看到有效提交得到了AC以后,都会大呼一声“你好能啊!”,反之,如果得到了RJ的话,就会化身为喷子,说xx句“你能不能行啊!”。大家比赛的都十分紧张,这样的大声呼喊未免会引起旁边队伍的注意。 当然牛牛战队交题的时候也很小心,一旦这一发出现了RJ,下一发有效提交一定能获得AC。 比赛结束了以后,旁边的一支队伍愤怒的跑过来说:你们比赛的时候吵不吵啊,一直在这大吼,吼了这么多句! 激烈的争吵引起了吃瓜群众的注意,吃瓜群众问道:吼了多少句啊,这么讨厌的吗 “啊……我也记不清了,大概是在[L,R]这个区间吧” 作为吃瓜群众的你,想根据这个信息算出,这个队伍有多少种有效提交结果序列的可能呢? 输入描述: 输入数据包括单组数据、多组询问。输入第一行包含一个整数x(2≤x≤100000),表示牛能在RJ状态下会说“你能不能行啊!”的句子数量。 第二行包括一个整数Q(1≤Q≤10 5 ^5 5 ),表示询问数量。