dp
goto_1600
我何来寂寞,哪有寂寞可言。
展开
-
dp 背包初级
背包问题:每个物品w千克 v个价值 要想在输入的we限定重量内 价值最高。AC代码:#include<stdio.h>#include<string.h>#include<algorithm> using namespace std;int dp[1000][1000];int we;int v[1000];int wm[1000]; in...原创 2020-01-31 19:19:28 · 197 阅读 · 0 评论 -
最大公共子串序列
例如串1ABCE 串2为BCDE 那么他们公共子串就是BCE这里要用到动态规划dp思路:dp[i][j]指的是字符串s1和s2的最长公共子序列要求它的下一个i+1 j+1时候的状态要分情况讨论:情况1:如果他们末尾的字母相等,那么该字母肯定是子序列中的一个dp[i][j]+1就行。情况2:如果不相等,就要取串1i+1和串2j的最大公共子序列和串i和串2j+1的公共子序列 这两个的最优解,...原创 2020-01-31 21:04:08 · 206 阅读 · 0 评论 -
The Hard Work of Paparazzi(dp巧妙优化)
链接题意:r,n代表一个r * r的矩阵,n代表有n个金币,初始时间是0,现在你站在(1,1)位置,然后给出n个金币出现的位置(x,y)和出现的时间t,这个金币只在t这一分钟出现,过了t就消失,然后保证给出的t是严格递增的,求你能获得的最大收益。每分钟你能向四周移动一个单位。思路:dp[i]以第i个结尾的最大值,只想到on^2的做法,但后来发现因为r很小,t又是递增的,第二层循环只要枚举(i-4r~i-1)就行了,为什么呢,因为i-5r一定能更新i-3*r,那么如果枚举所有点,这样就多余了。复杂度O(.原创 2020-10-24 12:10:19 · 391 阅读 · 1 评论 -
数位dp 数位和
#include<iostream>#include<cstring>#include<vector>using namespace std;const int N=11;int f[N][N][110];int p;void init(){ for(int i=0;i<=9;i++) f[1][i][...原创 2020-04-24 20:38:55 · 424 阅读 · 0 评论 -
Windy数 数位dp
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#include<map>#include<vector>#include<queue>#include<se...原创 2020-04-24 20:12:29 · 239 阅读 · 0 评论 -
数位dp 度的数量
解题报告:这道题着实是数位dp的入门题了,不得不说yxc的新方法真的太好用了,我们可以构建一颗包含数位的一棵树,然后层层递归下去,设每一个数位是从0~an-1 -1 的,这些我们后面的数都可以随便选,层层递归下去,然后每个题目都不一样都要预处理出来数左边的每一个值,最后答案就是左边加上右边,就是该数本身的大小。#include<iostream>#include<cstr...原创 2020-04-24 19:46:22 · 333 阅读 · 0 评论 -
1013. 机器分配
解题报告:这道题是分组背包问题的模型,每组物品只能选1样,并且总体积不能超过m,求路径的时候用一个way数组记录一下,从n开始反推就完事了,他都没有要求输出字典序最小,如果需要输出的话,要以f[1][m]为起点推,尽量让字典序小的放在前面。#include<iostream>using namespace std;const int N=11,M=16;int w[N][...原创 2020-04-16 11:46:52 · 232 阅读 · 0 评论 -
多重背包 二进制优化
思路:原来的复杂度是nms把物品拆成二进制形式,比如说10个物品,其实可以拆成1,2,4,3,1和2和4能表示1~7的所有数,加上三,刚好能表示1到10的所有物品,分组的方式也比较简单,从1开始选,每次乘2,直到不能乘的时候,然后作差剩下的数,然后绑在一块,用01背包模型就可以了#include <iostream>#include <cstring>#include <algorithm>#include<vector>using namesp原创 2021-09-14 16:48:40 · 367 阅读 · 0 评论 -
CCA的区间 思维sosdp 区间反转trick
思路:可以反转一个区间 ,就代表 取两段 互不相交的合法区间,这里互不相交指的是对于任何一个元素,两段区间不存在都有该位的情况,合法也是,然后最大值,由于每个数是二进制位,说明每一段区间长度不超过 24,所以初始值dp[i]=i,如果i能取到,我们可以子集dp代表 i的子集的最大值,然后枚举它的补集,可以发现,这两个刚好不相交,所以不用判断是否相交,然后复杂度 nlogn,n<=224n logn,n<=2^{24}nlogn,n<=224code#include<bits.原创 2022-03-06 00:08:51 · 220 阅读 · 0 评论 -
5917. 同源字符串检测 暴力 dp 字符串匹配
link题意:给定目标字符串s1,s2问是否存在一个字符串能满足生成s1并且生成s2,s1和s2中会有一些数字,数字可以任意分割成某些字符。len<=40任意连续数字不出现超过3个len<=40 任意连续数字不出现超过3个len<=40任意连续数字不出现超过3个思路:dp[i][j][k]dp[i][j][k]dp[i][j][k]代表匹配到s1的i处,匹配到s2的j次,当前s1比s2的通配符多k个,最后check(dp[n][m][0])就可以了。如何转移呢,分类讨论即可,del原创 2021-11-01 14:58:53 · 195 阅读 · 0 评论 -
E. Arena dp计数
link题意:给定有n个人,n个人可以取1~x这些取值,n<=500,x<=500 每一轮当场活的人会同时朝所有在场的人开一枪,也就是hp-=1,最后如果全死算是一种方案,问有多少方案。n<=500x<=500n<=500 x<=500n<=500x<=500思路:考虑dp,dp[i][j]dp[i][j]dp[i][j]代表考虑前i个人,取值<=j的合法方案数,可以发现如果在场一个人是对答案没有贡献的,dp[i][j]dp[i][j]dp[i]原创 2021-11-01 14:43:18 · 383 阅读 · 0 评论 -
F2. Korney Korneevich and XOR (hard version)
link题意:给你长度为n的数组,n<=1e6,a[i]<=5000满足递增的子序列求出的值有哪些,求出具体方案。思路:正解是maxn^2的,我们从前往后遍历,由于会有很多重复的转移,我们考虑用一个ne数组代表多少个数能被x转移去重,g[x]数组代表以x为结尾,前面有多少个数能和x异或出来,由于ne数组是递减的,每次下降的时候要判断是否大于x,因为要判断是否是严格上升子序列,然后放到新的vector里面,用完以后记得把当前遍历完的清空。#include<bits/stdc++.h原创 2021-10-25 20:32:36 · 447 阅读 · 0 评论 -
leetcode 546. 移除盒子 区间dp
link题意:每次可以删除连续的相同的数,删除k个贡献为k*k,问删完的最大贡献。n<=100思路:一开始想到的是区间dp,但是二维不知道怎么转移,看了题解,只能说是太难想到了,三维dp[i][j][k]dp[i][j][k]dp[i][j][k]代表删除i~j并且i是最后一次删除,并且最后一次删了k个元素的最大值。最后答案就是maxkdp[0][n−1][k]max_{k}dp[0][n-1][k]maxkdp[0][n−1][k],为什么这样一定能求出答案呢,有一个重要的性质是一定能构原创 2021-10-13 13:36:20 · 222 阅读 · 0 评论 -
Gourmet choice DP+拓扑
LINK题意:给定∑i=1n∑j=1m\sum_{i=1}^{n}\sum_{j=1}^{m}∑i=1n∑j=1ma[i]<b[j],也就是所有ai和bj的关系我们是知道的,最后求最大值最小的构造方案,如果无解输出NO思路:先把相等的点用并查集维护一下,然后我们只维护<的关系,因为>反向建图就行了,然后跑拓扑DP,f[i]>=∑j=premax(f[j]+1)f[i]>=\sum_{j=pre}{max(f[j]+1)}f[i]>=∑j=premax(f[j原创 2021-10-04 21:47:09 · 158 阅读 · 0 评论 -
AtCoder Beginner Contest 217 F Make Pair(区间dp)
link题意:有2*n个人,有m对好关系,每次只能删除相邻的好关系,问有多少种方式删完所有人。n<=200 m<=n∗(2n−1)n<=200~m<=n*(2n-1)n<=200 m<=n∗(2n−1)思路:由于n很小,考虑区间DP,dp[i][j]删完i~j的所有方案数,可以发现,区间长度为奇数的时候方案一定是0,是没有意义的。那么为了防止重复计数,我们考虑j这个数匹配哪一个数,我们用vector存储,v[a]里存储与a匹配的所有数。那么ve原创 2021-09-27 14:07:08 · 274 阅读 · 0 评论 -
hdu 6889 数位dp Xor
题意:思路:数位dp,考虑设计状态,第四个条件很好满足,设计一个flag3为状态位就可以了代表是否已经大于w,flag2,flag3代表是否到达枚举x和y的limit,那么第三个条件怎么设计呢,考虑稍微改变一下柿子,x−y<=k && y−x<=k x-y<=k~ \&\&~y-x<=k~x−y<=k && y−x<=k 那么就好办了,考虑x-y+k只有[−1原创 2021-09-21 20:26:34 · 197 阅读 · 0 评论 -
ICPC 沈阳M - United in Stormwind SOSDP+FWT+容斥
题意:题意是真的难懂,求题目集(0~1<<m)中满足>=k对不同的试卷,两张试卷不同当且仅当至少存在一位不同,而且该位在题目集里。 n<=2e5 m<=20思路:我们可以把a和b当做0和1处理,我们可以先求出i xor j =ki ~xor~ j~=ki xor j =k的对数,为什么处理呢?因为对于任意某个位置为1的话那么就说明这两个试卷是不同的。怎么处理呢?可以fwt,a自己卷自己,先把a[0]减去n,然原创 2021-09-15 18:49:52 · 1345 阅读 · 2 评论 -
树形dp 优化 ICPC南京 M.Monster Hunter
Link题意:有n个点形成一棵树,每个点的贡献是他自身的value和他目前存在的直系儿子的value之和,求依次求出删除0~n个节点的最小贡献。思路:考虑dp[i][j][k],到了i选了j个节点,当前这个节点删不删,那么显然很好转移,当父亲节点和该节点都是存活的情况下,会多额外贡献子节点的value.因为有了状态位,但是如果朴素转移会T,如下for(int i=siz[u]-;i>=0;i--){ for(int j=0;j<=min(i,siz[v]);j++)但是类似原创 2021-09-15 14:57:47 · 341 阅读 · 0 评论 -
2021 银川B DP
题意n个数分为要求分为1~n个子数组,每个子数组贡献为最大值减最小值n=1e4思路考虑dp ,dp[i][j][k]代表前i个数分为j个组,当前到了0/1/2/3状态,0代表最大数和最小数都没选,1代表选了最大数,2代表选了最小数,3代表俩数都选了,转移即可。由于8e8的空间,需要考虑滚动数组来优化。代码//#pragma GCC target("avx")//#pragma GCC optimize(2)//#pragma GCC optimize(3)//#pragma GCC opt原创 2021-08-15 21:30:49 · 257 阅读 · 2 评论 -
leetcode 盈利计划
思路:dp[i][j]代表不超过i 至少j的方案数,然后就很好转移了,第二维可以是负数,但是负数可以当作0处理。const int N=110;const int M=10010;const int mod=1e9+7;int dp[N][N];//最多用了i个人,利润不超过j的方案数class Solution {public: //dp[n][m] int profitableSchemes(int n, int m, vector<int>&.原创 2021-06-14 22:42:38 · 315 阅读 · 0 评论 -
Subsequences (hard version)
题意:给你一个长度为n的字符串,选择不同的k个子序列的最小花费,花费为n减去子序列长度思路:dp ,dp[i][j]代表以i结尾,长度为j的不同的子序列个数,注意去重,枚举前面如果末尾的单词一样就减去前面相同长度的贡献。#include<bits/stdc++.h>using namespace std;#define int long longconst int md=1e9+7;int a[20];int Pow[20];int len[110];int dp[210][原创 2021-04-17 15:30:10 · 204 阅读 · 0 评论 -
牛客小白月赛30部分题解
思路:是dp吧, 一开始没想到,瞄了一眼题解,线性dp,dp[i][2]dp[i][2]dp[i][2] 代表考虑前1~i个不同的数获得的最大值,0表示当前第i位不选,1代表选了,转移就不用说了,我预处理了每个数出现的次数,然后排序,去重使得dp不具有后效性。代码:#include<bits/stdc++.h>using namespace std;typedef long long ll;#define int long long #define debug printf("--.原创 2020-12-06 22:17:50 · 396 阅读 · 0 评论 -
D. Checkpoints
D题链接题意:有n个点,每个点可以放1也可以不放1,某个人从1开始挑战,包括1,n都要挑战,挑战成功的概率和失败概率一样都是1/2,如果失败了就会回到离i这个点最近的1的点,问最后通关(挑战成功n)的期望步数。思路:概率论纯属没有学好,看了题解期望原来是有可加性的,对于任意100000..1 0 0 0 0 0..100000..这样的序列,可以构成一个关卡,最后期望就是E的总和。然后我们计算子关卡的期望步数,E[i]=E[i−1]+1+1/2∗E[i]+1/2∗0E[i]=E[i-1]+原创 2020-12-06 22:13:30 · 450 阅读 · 2 评论 -
codeforces1453 E. Dog Snacks
题目链接题意 : 给你一棵树,每个点有一个零食 ,某个人从1号根节点出发,每次尽量走最近的点,最后走完回到1号点,问最小的k。思路:本来想的是二分+check 发现不可做啊,然后看了别人的题解,原来是有规律的,这道题确实和ccpc秦皇岛的蛮像,也是用的树形dp和贪心的结合,假设我们以u为根(u不是根节点的情况),那么对于每个儿子v所要满足k>=f[v]+2k>=f[v]+2k>=f[v]+2 其中k是能走的最大的范围 f[v]是子节点最浅的位置,由于这个题的特殊性,每次遍历完子树,原创 2020-12-06 21:59:58 · 402 阅读 · 0 评论 -
cf E Make it increasing
题意:题目大意:给出一个长度为 n 的序列,现在有 m 个位置被锁定,也就是无法进行操作,每次操作可以选择一个没有被锁定的位置,将其更改为任意数值,现在问最少进行多少次操作,可以使得整个序列变得严格递增思路:有个小技巧,看了大佬的博客才明白的,就是每一位都减去它的下标,这样判断起来,只需要判断锁住的元素是单调不下降的,就合法了,然后该题就转换成求k段操作数最少,由于每一段是独立的,那么考虑一段,有个结论最少操作数就是len-最长不下降子序列长度,那就分别求每一段就行了,加两个哨兵可以更有效的做题,然.原创 2020-10-29 17:18:00 · 400 阅读 · 0 评论 -
D - Painting Square (dp)
给定长度为n的正方形,每操作一次可以将一块正方形切为4部分,问操作k次能得到多少不同的图形样式,每次只能切中间,所以偶数肯定不能继续切了。思路:我们发现每操作一次n就会变成(n-1)/2dp?dp[][]代表前i层操作j次的方案数,如何转移呢?看了博客有个朴素的转移法就是枚举上一次的四块操作数,那复杂度是不能接受的,我们可以上下两块分为两组,先用ans数组预处理出来,由于组内是有序的所以两层循环都从0开始,这样就将复杂度变成了(30*n^2)是可以接受的。代码:#include<bits/st原创 2020-10-29 16:08:34 · 275 阅读 · 0 评论 -
移动服务
思路:dp[][][]代表考虑前i个请求,除了本位置之外的另外两个待在j和k这个位置,原本以为开4维然后发现。。有一维那个服务员的位置是确定的所以不用开,然后这个转移是常用的第二种转移方式,但注意服务员位置不能重复。ac代码:#include<bits/stdc++.h>using namespace std;const int N=1010,M=220;int f[N][M][M];//考虑前i个目前的服务员到达的是j倒数二个到达的是k int n,m;int c[M][M].原创 2020-10-22 17:15:44 · 243 阅读 · 0 评论 -
饼干 (贪心+dp+奇妙转换)
思路:dp[][]代表前i个小朋友发j个饼干的最小怒气值,由于排序不等式的证明,所有怒气值最高的小孩应该发的饼干是最大值,依次递减,我们先排序,然后记录在数组中原来的值,但是状态转移很难想啊,是类似整数划分,最后有几个饼干是等于1的,如果有k,K>0那么就可以由f[i][j]=min(f[i][j],f[i-k][j-k]+(i-k)*(sum[i]-sum[i-k]));,如果等于0的时候呢,由于这个怒气值取决于这个图形的形状,那么直接把整体往下-1就行了,最后比较ex的是要输出方案??啊这,那.原创 2020-10-22 16:44:54 · 234 阅读 · 0 评论 -
Polygon
题意:有n个点构成的环,环上的边t代表+,x代表*,选择先断一条边,然后问能获取最大值的方案和最大值。思路:一开始想的是dp[l][r]代表l~r之间运算出来的最大值,结果发现不太行,因为l到r之间的数可能是负数,负数乘以负数可能会更新最大值那么我们多开一维记录最大值和最小值。最后就是细节问题了,我们可以枚举选哪一条边那复杂度就是on4了,还有另外一种做法也是区间dp的通用技巧,就是扩大一倍数组,可以有效降低到on3。昨天因为dp[i][j][0]=min(dp[i][k][0]+dp[k+1][j][.原创 2020-10-22 15:45:24 · 248 阅读 · 0 评论 -
选课
题意:某个课只有它父节点选的时候他才能选,问n个点构成的树,选m个课的最大学分数。思路:构建一个虚拟节点0,那么0就是必选了,把选的课数量+1,对问题造成的影响是等价的,然后就是熟悉的分组背包问题了,早上卡了很久,因为要空出一格来放父亲的节点,然后对于背包dp的顺序是不能改变的,1物品组2体积最后是决策,里面只能选m-1个点,因为要留一个给自己放。ac代码:#include<bits/stdc++.h>using namespace std;const int N=310;int .原创 2020-10-22 15:40:30 · 216 阅读 · 0 评论 -
扑克牌 概率dp
题意:从54张牌中抽牌,问抽到a张红,b张黑,c张方,d张梅的概率,当抽取到大王和小王的时候,会固定抽期望步数最少的牌。求最小的期望步数。思路:期望dp ,dp(a,b,c,d,e,f),a,b,c,d,代表前4种牌的数量,e,f代表大王和小王的状态,要注意判断不合法的情况,即所有牌都抽完了,还是没有得到想要的局面。然后我做的时候理解错题意了,把题意理解炒成期望步数了,其实抽到小王大王的时候选择是固定的,而没有四个分支。#include<bits/stdc++.h>using name.原创 2020-10-22 15:36:52 · 435 阅读 · 1 评论 -
金字塔
题意:给你一个字符串,问你有多少个树形结构。思路:有dfs序那味道了,哈哈哈哈,然而是个区间dp,f[l][r]代表字符串从l到r中有多少种树形结构,状态转移不太好想,为了达到不重不漏的目的,我们通过枚举k来枚举第一个子树出现的大小,然后,只有在两端点相等的时候才能执行,因为最后要回到该点。其实k枚举到r-2或者r-3都是可以的,因为区间长度如果为2是不合法的。ac代码:#include<bits/stdc++.h>using namespace std;const int mod=.原创 2020-10-21 22:39:01 · 344 阅读 · 0 评论 -
积蓄程度
题意:找一个点作为源点,问能往周围流的最多的水流。树形dp,dp数组代表以i为根的能流的所有水流,转移很简单,看代码,然后我们要处理一下从父节点流下来的值。如图。之前wa了三十分钟,是因为转移的时候忘记考虑了父节点子树给他的贡献,从上面留下来的水流包括父节点父节点流下来的水流+子树的水流,然后别忘记特判一下当两个端点的时候,两端都可以流。#include<bits/stdc++.h>using namespace std;const int N=200010;typedef lon.原创 2020-10-21 22:13:42 · 256 阅读 · 0 评论 -
K - Appleman and Tree
题意:给定一棵树,将树分成k个连通块,并且每个连通块内只有一个节点的方案数。思路:这个实在是想不出来啊,标解是开个dp[u][2]数组,表示只考虑u这颗子树并且u这个节点是否在有黑棋子的连通块中的方案数。初始化就是如果黑色dp[u][1]=1,否则dp[u][0]=1;转移也很骚:枚举每个子树,由于乘法原理我们发现子树之间是相互独立的,dp[u][1]=dp[u][1](dp[j][0]+dp[j][1])+dp[u][0](dp[j][1])dp[u][0]=dp[u][0]*(dp[j.原创 2020-10-21 18:25:52 · 257 阅读 · 0 评论 -
A - Distance in Tree
题意:给你一棵树,让你记录树上两点距离为k的点对数。思路:dp[i][j]代表考虑i这颗子树,与它距离为j的点数量,dp[i][0]就是1了,然后dfs处理一下就可以,那么它就是答案的一部分,还有一部分就是把i当做中转节点,从u开始递归,枚举它的每个子树,ans+=(dp[u][tt]-dp[j][tt-1])*(dp[j][k-tt-1]),最后别忘记除以二,最后有点小疑惑,为什么这样就是答案了呢,会不会重复或者漏算呢,首先dp[i][k]加起来肯定是不重复的,然后画画图发现把u当做中转的也不会有重.原创 2020-10-21 18:16:40 · 552 阅读 · 0 评论 -
B - Zero Tree
题意:每次可以将包含1的节点的子树加1或者减1,问最小的操作数让整棵树变成0;解题思路:由于每次操作都要带上1,那么我们把1当做根节点,然后我们发现他的操作数与子树有关,先不考虑u这个节点,仅考虑他的子树,那么操作数有上升的也有下降的,那就是启发我们开两个数组,up,down记录上升的次数和下降的次数,状态方程转移:up[u]=max(up[j]),down[u]=max(down[j]),然后再考虑u这个点,先把down和up都计算到val中,如果val大于零down+=val,否则up-=val.原创 2020-10-21 18:09:04 · 372 阅读 · 0 评论 -
I - Tree with Maximum Cost
题意:选择一个点作为根节点,然后每个顶点到它的花费为距离那个顶点的值。求最大值。思路:也是树形dp,dp[i]代表考虑以i为根节点,他的子树对他的花费,sum[i]代表i整颗子树的节点个数和,那么dfs两次就行了,第一次dfs预处理出来sum和dp数组,第二次处理出每个点的答案。u节点的答案就是ans[u]=dp[u]+(all-sum[u])+ans[p]-sum[u]-dp[u]=all+ans[p]-2sum[u];AC代码:#include<bits/stdc++.h>usin.原创 2020-10-21 17:59:01 · 199 阅读 · 0 评论 -
F - Computer
题意:给定一棵树,求出每个点到树上所有点的最大距离。思路:先dfs预处理出来 考虑u这颗子树,往下走的最大值和次大值,然后每个点的最大值,来源一下面的最大值和它根节点往上走的最大值再取max,那么往上走的情况有两种例如下图:p代表u的父节点,根节点往上走的途径有两条,一条是继续往他的父节点走,就是up[j]+w[i],还有一条就是它往下走,往下走就要判断一下往下走的最大值是否经过u这个点,如果经过了就只能用次打值来更新了,否则可以用最大值。#include<bits/stdc++.h>.原创 2020-10-21 17:51:00 · 281 阅读 · 0 评论 -
2020CCPC秦皇岛 k Kingdom’s Power
题意:有无数个军队可以从树根1出发,每花费一个点可以让军队走一步,问遍历完整个树的最小花费。思路:先记录每个节点的高度,用节点根据它子树的高度的高度来排序,然后节点的高度为子树的最高高度+1,然后类似树形dp,从上往下递归h和与从下往上走的值取min。最后把所以的根节点的值加起来。#include<iostream>#include<cstring>#include<vector>#include<algorithm>using namespac.原创 2020-10-19 12:00:48 · 1159 阅读 · 0 评论 -
Maze 概率dp
题意:有一棵树,主人公要从1开始走,逃生,问逃生的期望步数,在1这个点 不可能死也不可能逃生,在别的点有ei的概率逃生,ki的概率死亡并且回到1这个点。思路:真的是难推啊,我们定义f数组为在i这个点逃生的期望步数,由于是无向图,我们先从叶子结点考虑,f[i]=0e[i]+ k[i]f[1] + (1-ei-ki)(f[fa[i]]+1)对于普通节点f[i]=0e[i]+k[i]f[1]+(1-ei-ki)/m(f[fa[i]]+1)+zigma((1-ei-ki)/m*(f[child[i]]).原创 2020-09-26 13:38:54 · 246 阅读 · 0 评论