![](https://img-blog.csdnimg.cn/20201014180756757.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
动态规划刷题
本人的dp刷题记录
那页
这个作者很懒,什么都没留下…
展开
-
2020 ICPC沈阳H题(dp+二分)好题
TP由于题目中出现了非常多的1e9范围的数据,所以能够拿来跑循环的一个是n(套餐种类),一个是m(每次哪天租几次),同时∑qi<=3e5\sum{qi} <= 3e5∑qi<=3e5也很令人在意,然后发现几乎不可能再m上直接设置状态,因为时间复杂度会变得非常不合理,所以选择在∑qi\sum{qi}∑qi上转移,每次租车都属于某一天,那么我们可以根据相隔天数讨论,如果符合可以直接转移,否则在∑qi\sum{qi}∑qi上二分,由于我们在开始时会对天数排序,那么越往后天数也会越大。知道我们找原创 2021-11-19 13:32:20 · 722 阅读 · 0 评论 -
CF734E Anton and Tree 树上缩点
传送门思路把连通块缩成一个点,然后就可以直接转化成一个相邻点颜色不同的树。那么把这颗树变成同色,只需要(树的直径+1)/2就可以了。很简单的思路,然年被我实现搞出了无数个问题。总之就是非常离谱离谱的提交记录。#include "bits/stdc++.h"#define pii pair<int,int>using namespace std;const int N = 2e5 + 10;int head[N << 1];int head2[N <<原创 2021-08-16 21:26:25 · 105 阅读 · 0 评论 -
CF14D Two Paths 树的直径
求树上两条不相交路径长度乘积最大值。暴力枚举断边求两个子树直径乘积即可。#include "bits/stdc++.h"#define pii pair<int,int>using namespace std;const int N = 1e5;int head[N];int cnt;struct node { int next, to, id;} a[N];void add(int u, int v, int id) { a[++cnt].to = v;原创 2021-08-16 15:55:53 · 99 阅读 · 0 评论 -
P1725 琪露诺 - 单调队列优化dp
虽然只是一道绿题,但也挺有意思的。题意你需要从0跳到n,每个点上有价值A[i],到达一个点就能得到A[i]价值,但是你每次只能跳到[i+l,i+r][i+l,i+r][i+l,i+r]上,问超过终点的最大价值是多少。朴素的dp很好写,当然,速度也很拉跨。我们能发现每次转移到i的点都是在[i-r,i-l]间的,这个可以用一个单调队列来维护,那么唯一要解决的问题就是入队时我们要保证队列内没有pos>i-l的,这一点我们可以延迟入队,在遍历第i个点时再推入i-l,就解决了这个问题。#include原创 2021-08-06 18:43:19 · 111 阅读 · 0 评论 -
P2365 任务安排 -斜率优化模板(纯代码+注释)
如果理解斜率优化的话就是纯板子,不理解的推荐看一下洛谷题解区第一篇,讲得很透彻。要注意的一些都在注释里了。///斜率dp/// 初始状态0入队。/// 每次使用一条和i相关的直线f(i)去切维护的凸包,找到比此时i要小的最大状态为f(j),更新 dp(i)。/// 加入新dp(i)时如果新的与队尾的斜率小于前一个,那么剔除///b 由不与j相关项构成///y 由纯j项构成///k,x由j,i混合项构成,其中k是与i相关///可与二分,平衡树,cdq分治优化使用#include <b原创 2021-03-01 19:58:32 · 163 阅读 · 0 评论 -
Typing Contest - hdu 7033背包
枚举总的f大小作为背包容量即可,f为0的可以直接入答案,难就难在发现f的枚举有效范围在[1,sqrt(n+2)]之间,然后就是输入输出,直接用浮点或者什么双精度肯定是错的,建议用字符串模拟读入输出,不然会wa到怀疑人生。#include "bits/stdc++.h"using namespace std;#define int long longconst int N = 2e4 + 100;int f[N];long long s[N];long long dp[N];inline v原创 2021-08-06 11:09:51 · 82 阅读 · 0 评论 -
CF449D Jzzhu and Numbers
传送门很有意思的题目,考验对容斥的熟悉程度和对状压dp的理解。首先我们再在翻译的基础上转化一下题意。设f[i]为恰好i个1,g[i]为至少i个1。也就是一个子集满足&的结果1的个数恰好为0个。因为至少0个的包含至少一个的,形成了容斥。 f[0]=∑i=0(−1)ig[i]\ f[0] = \sum_{i=0}(-1)^ig[i] f[0]=i=0∑(−1)ig[i]故我们的任务变成了统计g[i]。这时候用SOS dp,令形如i&k==i的像这样进行转移dp.原创 2021-07-23 17:03:46 · 143 阅读 · 0 评论 -
League of Legends -- 2021牛客暑期多校训练营2
题意:把给出的n条线段分成k组,使得每组都保证线段有交,或者是一条线。求最后所有k个组交的长度的和。想做这道题首先要搞清楚几个点:1,怎么处理复杂关系的区间。2,知道是dp之后,怎么推转移方程。3,如何进行优化。这里面最难想的可能是第一个点了。因为在做这道题前我已经假定这道题是dp题,于是我首先试着写一下转移方程for(int i = 1;i <= 0;i++) //n person for(int j = 1;j <= k j++) //k group原创 2021-07-20 09:26:24 · 408 阅读 · 1 评论 -
P1220 关路灯
题目描述某一村庄在一条路线上安装了 nn 盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少)。老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电。他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边的路灯原创 2021-07-10 10:50:29 · 191 阅读 · 0 评论 -
Accumulation Degree -换根dp
因为这个换根比较简单,只简述一下要维护的东西:1,每个节点维护一个weight[],表示从叶子到根的方向,这个点最多能接纳的流量。2,边权。所以画画图,手动模拟一下就得出了以下转移:void dfs2(int u,int fa){ for (int i = head[u]; i ; i = a[i].next) { int v = a[i].to; if (v == fa) continue; int now = res[u] - a[i].原创 2021-07-08 15:30:21 · 255 阅读 · 2 评论 -
小仙女过生日啦 -凸三角形三角剖分
凸三角形的三角剖分规定了三角形为凸多边形。故对于任意多边形,要判断是否存在凹点,此点不能剖。这题是运用区间dp求三角剖分原理解决剖分出的三角形里最大的一块的面积的最小值。#include "bits/stdc++.h"using namespace std;//const int maxn = 2000000 + 9;struct node { double x, y;} a[2000];double f[2000][2000];int n;double calc(node原创 2021-07-07 08:30:31 · 297 阅读 · 0 评论 -
和与或---动态规划
链接:https://ac.nowcoder.com/acm/problem/21336给你一个数组R,包含N个元素,求有多少满足条件的序列A使得0 ≤ A[i] ≤ R[i]A[0]+A[1]+…+A[N-1]=A[0] or A[1]… or A[N-1]输出答案对1e9+9取模首先分析题目,很容易知道每个A[i]的二进制位都只有一个能是1,假如没有0 ≤ A[i] ≤ R[i]限制的话应该可以直接组合求值。那么有这个限制该怎么办,既然我们每一个二进制位都只能用一次,那么我们就枚举二进原创 2021-05-20 20:33:26 · 145 阅读 · 0 评论 -
牛客21314 codeforces背包
传送门这是一个价值会随时间递减的背包,所以装入顺序会成为一个要点,如果推一下式子就知道哪件排前面比较好,pointsPerMinute*1.0/requiredTime即为权值。#include "bits/stdc++.h"using namespace std;#define int long longint dp[600000];struct node{ int maxPoint; int pointsPerMinute; int requiredTime;原创 2021-05-19 16:55:23 · 104 阅读 · 0 评论 -
P4302 [SCOI2003]字符串折叠 ---区间dp
题目描述折叠的定义如下:一个字符串可以看成它自身的折叠。记作S = SX(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) = SSSS…S(X个S)。如果A = A’, B = B’,则AB = A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) = AAACBB,而2(3(A)C)2(B) = AAACAAACBB给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。挺早以前就准备做的原创 2021-05-15 17:27:31 · 129 阅读 · 0 评论 -
合并回文子串
一个涉及到两个串区间的问题。第一次做这种,在dp里存了答案,发现维护的答案有点乱,最后把dp改成了表示能否形成回文。再每次比较一下当前的大小和最大值。还是不错的区间dp。#include<bits/stdc++.h>using namespace std;int dp[60][60][60][60];signed main() { int T; cin >> T; while (T--) { memset(dp,0,sizeof(原创 2021-05-15 16:38:11 · 62 阅读 · 0 评论 -
P1541 [NOIP2010 提高组] 乌龟棋 --dp
题目说刚好能走完而且只有4种牌,每种牌都不超过40。dp状态就出来了,就是4种牌每种已经用掉了几张。非常暴力的dp//// Created by SANZONG on 2020/7/31.//#include "bits/stdc++.h"using namespace std;int N , M ;int score[10000];int card[10000];int dp[42][42][42][42];int vis[10];int ans =0;int main() {原创 2021-05-12 20:27:59 · 103 阅读 · 0 评论 -
[SCOI2005]扫雷 ---水题
挺有意思的dp 思维题,比较简单直接看代码就行。```//// Created by acer on 2021/5/11.//#include <iostream>#include <cstring>using namespace std;typedef long long ll;#define int long longint dp[11000][2][2];int num[11000];int ans[1100];signed main() {原创 2021-05-12 20:08:15 · 50 阅读 · 0 评论 -
17867 明七暗七
数位dp+二分比较入门的数位dp,快半年没写过拿来练练手。dp是三维,分别是位置,当前数mod7,是否含有7,前两个很简单,第三位有点迷惑,不加就是只能过8%,但好像没有什么用。//// Created by acer on 2021/5/11.//#include <bits/stdc++.h>using namespace std;typedef long long ll;#define int long longint num[20];ll dp[20][10][原创 2021-05-11 21:15:33 · 118 阅读 · 0 评论 -
[2019杭电多校第三场][hdu6606]Distribution of books
dp好难呐这道题用到的知识点是dp+线段树+二分答案。简述一下解体流程。首先地看到求最小最大解想到用二分答案。二分答案需要验证是否可行,验证主要就是看能不能把一堆书以一个x为上限分出来k堆,如果这个x做不到分成k堆,那么肯定不行。再看如何验证,定义一个dp[i],i表示当前是第i本书,存的是前i本能分成的最大堆数。那么转移就是if(sum[i] - sum[j - 1 ] >= x)dp[i] = dp[j-1]+1;到此为止已经处理除了朴素的解。但是朴素的解很显然会T,接下来处理优化原创 2021-05-06 18:45:47 · 88 阅读 · 0 评论 -
Codeforces Global Round 14 E. Phoenix and Computers
刚开始自己想的是区间dp,写完之后发现一点问题调不出来,然后就搜了搜博客。大佬使用线性dp写的,很容易理解,下面贴了链接我就不多写了。大佬博客#include <bits/stdc++.h>using namespace std;typedef long long ll;#define int long longconst int N = 110000;int dp[600][600];int mod;ll F[N], invn[N], invF[N], bit[N];原创 2021-05-03 20:51:13 · 74 阅读 · 0 评论 -
P2634 [国家集训队]聪聪可可 树形dp
题意:求两个点之间所有边上数的和加起来恰好是 3 的倍数的点对有几个。树形dp可以解这道题。首先状态很容易确定,即id和当前点的子树距离。即dp[i][0-2]。表示子树里距离为1,2,3的点的数量。在根节点上很容易推得当前点上的贡献,即dp[u][(666666-j-a[i].w)%3]*dp[v][j]*2,乘2是因为要算两次。加66666是防负数。//// Created by acer on 2021/2/16.////判断子串,不同子串个数,所有子串字典序第i大,最长公共子串#i原创 2021-04-28 20:52:30 · 73 阅读 · 0 评论 -
[HAOI2015]树上染色 树形背包
这是一道很考细节的题。硬是怼着题解改了一小时的细节 。这题的主要思路就是把路径拆分成线段,走过一次相当于加一次线段。所以我们可以把走过和没走过的分成两块,而即将要走那条路作为我们状态转移的关键。故,当前边权值即为((走过的子树里黑色点没走的部分的黑色点)+(走过的子树里白色点没走的部分的白色点))* 当前边权,所以我们每次枚举父节点u子树里的黑色点个数,以及当前遍历到的子节点v子树里的黑点数,而当前边权就是u与v想链接的边。//// Created by acer on 2021/2/16.///原创 2021-04-24 16:04:57 · 58 阅读 · 0 评论 -
Flipping Game (组合数学,dp)
给了你一个合法状态和一个非法状态,首先必交两者差异,即不同的有几位,那么合法的位数即我们的初始状态,我们每次可以选l个从合法到不合法,相应的有m-l个从不合法到合法,那么转移方程就是 dp[j][i - l + m - l] = (dp[j][i - l + m - l] +dp[j - 1][i] * C[i][l] % mod * C[n - i][m - l] % mod) % mod;那么答案就是最后一轮并且正确数为n的dp[k][n]很简单的dp方程,很难想到的状态。#include &原创 2021-04-14 20:16:01 · 191 阅读 · 0 评论 -
P4141 消失之物 计数背包
经典题,考到的是背包的性质,对于技术背包可以这样做,经典01背包思路类似,今天还做到一个多重背包加权限的很类似是通过二进制分解加前后各一遍多重背包写出来的,可以参考。#include "bits/stdc++.h"using namespace std;const int MAXN = 3e5 + 10;int a[3000];int dp[2100];int ans[2100][2100];signed main() {// freopen("in.txt", "r", stdi原创 2021-04-11 21:08:23 · 81 阅读 · 0 评论 -
P1156 垃圾陷阱 背包
传送门有一说一我还是进入误区了,这题没啥技巧,关键就是不要尝试去减时间来判断是否死亡,只需要一直递增生命值就可以。#include "bits/stdc++.h"using namespace std;const int MAXN = 3e5 + 10;struct node{ int t,h,val;}a[101];int dp[25100];bool cmp(node c,node b){ return c.t< b.t;}int main() {/原创 2021-04-11 20:17:24 · 73 阅读 · 0 评论 -
UVA1437 String painter
题意:将两个等长字串涂色成一样需要几次。涂色:把连续字串涂成同一字符。解法:将全为空的字符串涂成目标很简单,一次区间dp,而把一个字串涂成另一个字串就多了几步,即相同位字符相同取前一位的次数,每次都要检查从开始到当前位置有没有更少的次数。#include "bits/stdc++.h"using namespace std;const int MAXN = 3e5 + 10;int dp[110][110];int ans[1100];int main() { freopen(原创 2021-04-11 18:57:31 · 62 阅读 · 0 评论