![](https://img-blog.csdnimg.cn/20201014180756923.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
动态规划
andyc_03
这个作者很懒,什么都没留下…
展开
-
2020复习——概率dp
1.普通概率【概率】P5104 红包发红包 2.概率dp【概率dp】poj 2096 Collecting Bugs 【概率dp】hdu 3853 LOOPS 【概率dp】hdu 4405 Aeroplane chess原创 2020-11-26 23:33:26 · 93 阅读 · 0 评论 -
【2020模拟赛day7】D. 回文子串
F[i][j]表示 i-j 的本质不同的会问子序列的个数举个例子:1 1 2 2 1预处理一下posl[c][l][r]和posr[c][l][r]表示字符c在区间l-r的最靠左/右的位置for(int len=1;len<=n;len++)for(int l=1;l+len-1<=n;l++){int r=l+len-1;for(int k是字符)f[i][j]+=f[posl[k][l][r]+1][pos...原创 2020-11-23 18:22:47 · 76 阅读 · 0 评论 -
【2020模拟赛day7】 A. 字符排序
考试的时候写的方案不对,得了55pts其实这道题目还是蛮明显的dp,然后需要记录一下状态,也就是方案每次更新f[i]的时候,顺便对字符串进行一下排序修改(重载一下小于号即可)代码#include<bits/stdc++.h>using namespace std;const int maxn=55;int t;char s[maxn];int has[30];struct sting{ int l; char ss[55];};st...原创 2020-11-23 00:09:49 · 48 阅读 · 0 评论 -
【树形dp】P2607 [ZJOI2008]骑士
将每个人讨厌的人连上一条有向边,构成了基环树森林,从每个树的环上断一条边,从两条边的点跑两次dfs,计算一下最大值加到答案里还有就是会超int代码#include<bits/stdc++.h>using namespace std;const int maxn=2e6+5;const long long inf=1e17;int n,root,cnt,v[maxn],fa[maxn],vis[maxn],head[maxn];long long f[m...原创 2020-11-17 23:02:22 · 129 阅读 · 0 评论 -
【2020模拟赛day6】C. 寻找序列
这道题是LCS和LIS的结合,考虑设计状态仍然是f[i][j]表示a串前i位和b串前j位能够得到的最长公共上升子序列然后呢考虑递推当a[i]==b[j] 枚举一维k 如果a[i]>b[k] f[i][j]=max(f[i][j],f[i-1][k]+1);当a[i]!=b[j] 直接f[i][j=f[i-1][j];这样的算法是立方级的观察发现,在计算i的时候,i-1行的k的大小已经确定,所以我们可以在计算时维护一个maxx去记录它至于方案,...原创 2020-11-15 21:40:30 · 70 阅读 · 0 评论 -
【2020模拟赛day5】D. 砍树问题
很显然是一个树形dpf[i][j]表示以 i 为根的子树中所属的连通块大小为 j 时的最大值那么可以用f[i][j]*f[son[i]][k]去更新f[i][j+k]得到代码#include<bits/stdc++.h>using namespace std;int n;const int maxn=705;int head[maxn],cnt;struct edge{ int to,nxt;}e[maxn<<1];void add(...原创 2020-11-15 20:44:56 · 215 阅读 · 0 评论 -
【2020模拟赛day5】B. 公共子串
用f[i][j]表示a串计算到i位,b串计算到j位时的最长公共子序列长度g[i][j]表示a串计算到i位,b串计算到j位时的最长公共子序列个数代码#include<bits/stdc++.h>using namespace std;const int maxn=5000+5;const int mod=1e8;char s1[maxn],s2[maxn];int len1,len2,f[maxn][maxn];long long g[maxn][...原创 2020-11-15 00:25:34 · 88 阅读 · 1 评论 -
2020复习——树形dp
1.poj3585(换根dp)2.P3647 [APIO2014]连珠线(换根dp)待填坑3.P3647 [APIO2014]连珠线(换根dp)待填坑原创 2020-11-14 23:35:20 · 84 阅读 · 0 评论 -
【树形dp】poj3585 Accumulation Degree
考虑树形dp,由于根不确定,所以我们先以1为根跑一次算出来g[i]表示i的子树内的最大值然后再一次dfs,计算F[i]表示以i为物资投放点的答案就得到了以上公式这个换根的过程很重要!!...原创 2020-11-14 22:34:53 · 96 阅读 · 0 评论 -
【状压dp】P1879 [USACO06NOV]Corn Fields G
记f[i][s]为第i行种草状态为s的方案数对于读入,我们要先处理出来每行的可行方案去一行一行推!代码#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;int n,m;const int mod=1e8;struct point{ int s..原创 2020-11-05 23:38:55 · 67 阅读 · 0 评论 -
【树形dp】UVA1218Perfect Service
注意这道题目inf开太大会爆掉int!!代码#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>using namespace std;const int maxn=1e5+5;const int inf=maxn;int n,tot,dp[maxn][3],head[maxn];str...原创 2020-09-13 22:30:44 · 75 阅读 · 0 评论 -
【动态规划】P1982 小朋友的数字
首先,dp算出一个最大连续子段和然后计算每个小朋友的分数,也就是ans[i]=max(ans[j]+sep[j])由于ans的数组是单调增的,所以可以每个位置的值可以直接modp代码#include<bits/stdc++.h>using namespace std;const int maxn=1e6+5;int n,p;long long suf[maxn],sep[maxn],ans[maxn];int main(){ scanf("%d%d",&am.原创 2020-08-19 23:48:43 · 180 阅读 · 0 评论 -
【牛客21303】删括号
手动模拟操作过程后,可以得到有用的信息为当前进行到s串和t串的位置所以我们记f[i][j]表示s串前i为能否于t串的前j位匹配对于当前的f[i][j],我们有以下情况1. s[i]=t[j] , f[i][j]=f[i-1][j-1]2. s[i]!=t[j] ①s[i]='(' 那么这个位置一定是无法匹配的! ②s[i]=')' 那么我们可以尝试删除s串末尾的匹配()对代码#include<bits/stdc++.h>using namespace std;...原创 2020-08-19 13:37:53 · 245 阅读 · 0 评论 -
【动态规划】牛客OI周赛15-提高组 回到过去
观察到通过不同的数额,去组成1e5,那么n就是log级别的,大约再460以内我们可以做两次dp,一次从前往后,f[i][j]表示前i种纸币能否组成金额j,第二次从后往前,g[i][j]表示后i种纸币能否组成金额j之后对于每种纸币,我们需要考虑前缀也就是f,能否组成k,后缀能否组成m-k()代码#include<bits/stdc++.h>using namespace std;const int maxn=1e5+5;const int maxm=460;int .原创 2020-08-06 00:07:11 · 126 阅读 · 0 评论 -
【poj1180】任务安排2
首先我们考虑正常dp的方式设f[i]表示前i个任务分批执行的最小费用,就可以得到转移方程f[i]=min(f[j]+sumt[i]*(sumc[i]-sumc[j])+S*(sumc[n]-sumc[j]))这里后半部分的S用到了“费用提前计算”的思想,将每次开机的时间提前加上了这样做的时间复杂度为整理得代码#include<bits/stdc++.h>using namespace std;const int maxn=3e5+10;long l..原创 2020-08-04 18:18:04 · 163 阅读 · 0 评论 -
【斜率优化dp】P3628 [APIO2010]特别行动队
首先定义f[i]为前i个士兵组成的最大战斗力直接计算的方式 for(int i=1;i<=n;++i) for(int j=0;j<i;++j) f[i]=max(f[i],f[j]+calc(c[i]-c[j]));其中calc为计算二次函数的值 c[i]为预处理的前缀和这样只能得到50分,我们还需要继续进行斜率优化设j的方案比k更优,有整理得 代码#include<bits/stdc++.h...原创 2020-08-04 17:02:06 · 127 阅读 · 0 评论 -
【状压dp】P3959 宝藏
这道题目有用的信息有我们已经把多少点加进生成树了,以及生成树的最大树高是多少。我们可以设f[s,i]为当前生成树已经包含集合S中的点,并且树高是i。这样就可以推出来f[i,j]=min(f[i,j],f[i',j-1]+cost) cost 是这条边的花费之后我们的操作如下:1、预处理出对于每个点能拓展的点的状态,还有点的深度3、枚举集合、所有需要被连向的点的最小边权求和乘深度,作为答案4、答案就是全集在1~n深度的最小值代码#include<bits/..原创 2020-08-04 13:14:35 · 123 阅读 · 0 评论 -
【线性dp】Acwing271. 杨老师的照相排列
考虑到安排第i个人的站位,他只能接着每一排已有的同学站,而不能隔开(否则就无法满足身高的性质)这样我们就可以设计状态f[a][b][c][d][e]表示第1-5排分别站a-e个人的方案书状态也就很好转移了代码#include<bits/stdc++.h>using namespace std;int k,s[6];long long f[31][31][31][31][31];int main(){ //freopen("a.in","r",stdin)..原创 2020-08-04 11:35:45 · 186 阅读 · 0 评论 -
【倍增dp】P1081 开车旅行
考虑到题目中给出了路径的生成方式,也就是说,从一个固定的点出发,路径是已知的,就可以想到了倍增的思想计算ga[i]表示i出发次近的点,也就是A开一次车到的地方;gb[i]表示i之后最近的点,也就是B开一次车到的地方然后处理f[i,j,k]表示k先出发,从i走j天的到达城市f[0,j,0]=ga[j], f[0,j,1]=gb[j]i=1 -> f[1,j,k]=f[0,f[0,j,k],1-k]i>1 -> f[i,j,k]=f[i-1,f[i-1,j,k],k]原创 2020-08-03 18:32:24 · 134 阅读 · 0 评论 -
【倍增dp】P3462 [POI2007]ODW-Weights
由于砝码质量成倍数,那么就可以把所有的盒子拆分成进制的形式,比如有1、2、4的砝码,那么容量为9的容器就写成(2,0,1)。把所有盒子的进制数组相加,累计每个进制位能放的数量。计算答案时,我们可以贪心的考虑,由小到大放砝码更优,对于每一个砝码,找到其重量对应的进制,如果进制位上有值,直接加入即可;如果没有,找到其前方距离它最近的有值的进制,如果找不到,输出答案结束程序。代码#include<bits/stdc++.h>using namespace std;const i.原创 2020-08-03 15:40:52 · 113 阅读 · 0 评论 -
【树形dp】P3155 [CQOI2009]叶子的染色
你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。由于题目的这一点要求,我们可以得出,叶子节点的着色方案只与其上方第一个有色节点有关,所以选择哪个节点做root都可然后就是树形dp,设f[u][col] 表示以u为根节点的子树所要染色节点数的最小值,然后就可以推出转移方程代码#include<bits/stdc++.h>using namespace std;const int maxn=5e4+5;const int..原创 2020-08-02 15:30:41 · 191 阅读 · 0 评论 -
【树形dp】P2986 [USACO10MAR]Great Cow Gathering G
和上一题的换根树形dp类似,这道就是加上了边权,仍是两次dfs即可但是这个题的输出会很大,ans初值要赋的大一点(要不然最后两个点会wa)代码#include<bits/stdc++.h>using namespace std;const int maxn=5e5+5;long long n,cnt,head[maxn];long long c[maxn],tot,dis[maxn],f[maxn],size[maxn],ans=100000000000...原创 2020-07-29 23:56:09 · 176 阅读 · 0 评论 -
【树形dp】P3478 [POI2008]STA-Station
这道题目要求换根,先跑一次dfs,求出dep和size观察到如果将root从u换成u的一个儿子v,那么v的子树(包括v)的dep将会-1,一共-size[v],其余节点的dep都+1,共计n-size[v]这样就可以再跑一次dfs,求出最大的位置即可代码#include<bits/stdc++.h>using namespace std;const int maxn=1e6+5;int n,cnt,head[maxn];struct edge{ int to,.原创 2020-07-29 21:42:37 · 208 阅读 · 0 评论 -
【树形dp】P1273 有线电视网
f[i][j]表示i的子树,供j个家庭看比赛的最大收入,然后初始状态也就是每个子节点(家庭)都是他们支付的金额,以及供应0个家庭的收入为0,状态转移就是分组背包的思想,每个子节点可以选择供应1个/2个/.../k个,最后统计最大值即可答案就是第一个f[1][i]>0的i的值,i倒序枚举,因为要求最大值代码有一点读入叶子节点的费用时,注意下标的问题!#include<bits/stdc++.h>using namespace std;const int maxn=.原创 2020-07-29 00:24:35 · 109 阅读 · 0 评论 -
【树形dp】P1272 重建道路
同样是树形dp,常规的设f[i][j],为i的子树(包含i),要有j个节点,删去边数的最小值这样我们就可以初始化一下f,f[i][1]=son[i] 对于i只保留自己,需要删去son[i]条边然后就是状态转移了 对于一个节点,它的状态可能有它所有的儿子更新(也就是分组背包的思想)f[i][j]=min(f[i][j],f[i][j-k]+f[to][k]-1)剩下的就是一些小细节了,比如可以删去这个节点与父亲节点的边,还有答案不一定在根节点的位置,要跑一下每个点,求最小值代码.原创 2020-07-28 23:54:29 · 103 阅读 · 0 评论 -
【树形dp】P1352 没有上司的舞会
f[i][0]表示i的子树,不选i的最大值,f[i][1]表示i的子树,选i的最大值树形dp基础代码#include<bits/stdc++.h>using namespace std;const int maxn=6010;int n,h[maxn],out[maxn],f[maxn][2];vector <int> G[maxn];void dp(int x){ f[x][0]=0; f[x][1]=h[x]; for(int i=0;i&l.原创 2020-07-28 20:46:17 · 119 阅读 · 0 评论 -
【区间dp】P4342 [IOI1998]Polygon
这道题目第一步划分时,可以直接将其延长一倍,然后就直接进行操作,剩下的就是普通的区间dp了由于dp的内容有乘积,有可能是两个负数的最小值乘来,所以需要维护一个最小值代码#include<bits/stdc++.h>using namespace std;const int inf=0x3f3f3f3f;int n,ans=-inf;int a[105];int f[150][150],g[150][150];char c[105];int main(){..原创 2020-07-28 20:00:50 · 94 阅读 · 0 评论 -
【区间dp】P1063 能量项链
这道题和石子合并一样,也需要进行拆环的操作,剩下的就是基础的区间dp代码#include<bits/stdc++.h>using namespace std;const int maxn=205;int n,a[maxn<<1],f[maxn<<1][maxn<<1];int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i.原创 2020-07-28 15:35:39 · 93 阅读 · 0 评论 -
【区间dp】P3146 [USACO16OPEN]248 G
典型的区间dp,直接枚举区间长度,更新时,注意只有左右两个区间相等才能去更新代码#include<bits/stdc++.h>using namespace std;int n,ans;int f[250][250];int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&f[i][i]); for(int i=2;i<=n;i++)//枚举长度 for(int .原创 2020-07-28 15:10:42 · 123 阅读 · 0 评论 -
【动态规划】P1941 飞扬的小鸟
用f[i][j]表示小鸟从开始到(i,j)的位置最小点击次数,具体转移方程见代码注意:要判断是否超过上边界代码#include<bits/stdc++.h>using namespace std;const int maxn=1e4+5;const int maxm=2005;int n,m,p;int up[maxn],down[maxn],low[maxn],high[maxn];int f[maxn][maxm];int pipe[maxn];int m.原创 2020-07-28 14:51:44 · 273 阅读 · 0 评论 -
【动态规划】P1541 乌龟棋
记f[a][b][c][d]为四张牌分别用了a,b,c,d张时的最大得分,然后可以递推代码#include<bits/stdc++.h>using namespace std;int n,m,x,a[355],f[125][125][125][125],col[5];int main(){// freopen("a.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf(.原创 2020-07-28 10:06:52 · 115 阅读 · 0 评论 -
【动态规划】P3842 [TJOI2007]线段
由于每行的线段都需要走完,且不能向上走,所以对于走完每一行,只有两种可能 1)在线段右侧 2)在线段左侧然后就可以基于这样的特点去更新下一行对于第i行,如果结束在左端点,那么它可能是上一行从右端点下来,走到左侧;也可能是上一行的左侧走到当前行右侧位置,再下来走到左面,就可以以此dp了代码#include<bits/stdc++.h>using namespace std;const int maxn=2e4+5;int n,l[maxn],r[maxn],f[maxn][原创 2020-07-27 20:39:11 · 160 阅读 · 0 评论 -
【背包dp】P5020 货币系统
通过观察可以发现等价的两个货币系统其实是子集的关系,也就是说把给定系统内的可以用其他面额的钱表示出来的金额删掉即可关于证明:如果A和B货币系统等价,且存在一个数字t属于A,不属于B,那么根据题意,t这个金额一定可以被B的元素表示出来,也就是说,从A集合中删掉这个数字,仍不影响A系统能表示出的所有金额代码#include<bits/stdc++.h>using namespace std;int t,n,a[105],amount[25005];int main().原创 2020-07-27 15:49:47 · 129 阅读 · 0 评论 -
【状压dp】[HDU1400 & poj2411] Mondriaan‘s Dream
对于棋盘上每个点,都有几种可能,1.不放 2.横放的前一个 3.横放的后一个 4.竖放的上一个 5.竖放的下一个由于题目要求每个格子都被填满,所以可能1不存在然后,我们可以考虑用1表示这个格子被放上了2/3/5这几种可能,然后通过二级制压缩状态对于每一行都有一个数值来表示当前行的状态 now 以及上一行的状态 pre我们可以通过dfs将所有的可能的两行之间的状态转移预处理出来再填写第d列的时候 有这样几种可能1.当前位置为可能2,那么就可以把下一个一起处理了,这时候要求上一行...原创 2020-07-27 12:47:13 · 140 阅读 · 0 评论 -
【动态规划】 基础题目(一)
1、P1359 租用游艇#include<bits/stdc++.h>using namespace std;int dp[205],n,x;int main(){ freopen("a.in","r",stdin); memset(dp,0x3f,sizeof(dp)); scanf("%d",&n); dp[1]=0; for(int i=1;i<=n;i++) for(int j=1+i;j<=n;j++) { scanf("%d",原创 2020-07-26 09:37:04 · 118 阅读 · 0 评论