
dp
wspl654321
。。。。。。
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
P4022 [CTSC2012]熟悉的文章
这真是个神dp 我肯定想不出来,太牛逼了题解假设我们知道了len[i]为i之前的最长匹配熟悉子串 我们可以二分答案,得到一个L 那么就可以得到 dp[i]表示匹配到i的最长熟悉长度 dp[i]=max(dp[j]+i−j)(i−len[i]<=j<=i−L)dp[i]=max(dp[j]+i−j)(i−len[i]<=j<=i−L)dp[i]=max(d...原创 2019-06-12 21:26:44 · 230 阅读 · 0 评论 -
dp水题
很多背包题原创 2017-10-26 11:40:08 · 244 阅读 · 0 评论 -
测试 3
chess 简单的搜索题,递归模拟,没啥优化剪枝。。。 不知怎么搞的’,’忘加了。。 然后走一步的特判在程序里错了,弄出去就对了。。。#include<cstdio>#include<iostream>using namespace std;struct st{ int maxn,cnt; };int a[11][11],b[11][11];int xx[]={1,1,-1原创 2017-10-25 15:07:16 · 273 阅读 · 0 评论 -
2016noip提高组day1 换教室
做这个题要先搞懂期望。。。 我还是不懂什么是期望。。。 但好像这个题的期望是距离乘概率。。。 所以这就是个期望dp f[i][j][0,1] 表示到i时间段,选了j个教室,选不选当前的教室 所以 有四种情况,前面选后面不选,前面选后面选,前面不选后面选,前面不选后面不选 方程就是f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j原创 2017-10-23 17:41:00 · 366 阅读 · 0 评论 -
愤怒的小鸟
一道状压dp题 把猪压缩为二进制,1代表能打死,0代表不能 然后预处理出任意两个猪组成的曲线,能打死那些猪,然后转移时或一下就行了 dp[i|bit[i][j]]=min dp[i]+1; 一个猪的预处理。#include<cstdio>#include<cstring> #include<iostream>#include<cmath>using namespace std;in原创 2017-10-22 09:56:27 · 348 阅读 · 0 评论 -
加分二叉树
想不到dp,写了个暴力,用记忆化搜索优化a了 枚举一个根,求出子树的最大值,记录下来,一点点向下 输出序列就记录下每个区间最大值的根,从他向下分,输出#include<cstdio>#include<iostream>using namespace std;int n,a[19999],toto,ans2[199999],dep[1999][1999],dp[1999][1999];in原创 2017-10-20 15:46:12 · 224 阅读 · 0 评论 -
飞扬的小鸟
dp 70%的方程很好想,100%的你可以先跳一次,再把上一次要跳的弄到后面去挑,因为这样你要先枚举矮的,从矮的向高处跳,而且这样你就可以从前一个的没管的位置向这跳,所以你要枚举这一个和前一个下管子的最小到上管子最大,才不会漏,而且你不能掉下来再跳,所以两个不能一块转移,最后掉,还有跳到m的,和上面一样的想法#include<cstdio>#include<iostream>#includ原创 2017-10-20 11:28:34 · 694 阅读 · 0 评论 -
子串
f是指选i这一位,sum是不选 然后选着一位的就等于选上一位地加上不选上一位的,选上一位的可以分为两种,独立成块的和不独立的 不选的就是之前所有的方案 然后把第一位滚动一下就行了#include<cstdio>#include<iostream>#include<cstring>using namespace std;int f[2][1999][1999],sum[2][1999][原创 2017-10-20 08:30:25 · 185 阅读 · 0 评论 -
饥饿的奶牛
和之前一个尼克的任务一样 f[i+1]=max(f[i],f[i+1]);f[i+1]=max(f[i],f[i+1]); f[a[i][j]+1]=max(f[a[i][j]+1],f[i]+a[i][j]−i+1); f[a[i][j]+1]=max(f[a[i][j]+1],f[i]+a[i][j]-i+1);#include<iostream>#include<cstring>#in原创 2017-10-27 11:23:22 · 410 阅读 · 0 评论 -
多米诺骨牌
f[i][j]表示前i个的差是多少的最小步 f[i][j]=min(f[i−1][j+a[i]−b[i]],f[i−1][j−a[i]+b[i]]);f[i][j]=min (f[i-1][j+a[i]-b[i]],f[i-1][j-a[i]+b[i]]); 递推过去,最后求最小差#include<cstdio>#include<iostream>#include<cstring>usin原创 2017-10-26 14:40:13 · 392 阅读 · 0 评论 -
洛谷 P1736 创意吃鱼法
一个简单的dp。 最长线是之前的最长的和前面零的个数的最小值 不过一开始我的min忘写了,编译器竟然不报错。。 尴尬了。。。#include<cstdio>#include<iostream>#include<cstring>using namespace std;int ans,m,n,f[2509][2509],dp[2509][2509],a[2509][2509],h[2509]原创 2017-10-26 15:40:55 · 268 阅读 · 0 评论 -
数位dp
转自http://blog.csdn.net/wust_zzwh/article/details/52100392 基础篇 数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位……数的每一位就是数位啦!之所以要引入数位的概念完全就是为了dp。...转载 2018-03-05 20:58:58 · 253 阅读 · 0 评论 -
HDU2829#Lawrence
dp[i][j]=dp[k][j-1]+cost[k+1][i] 可以证明cost符合四边形不等式 需要人去证明#include<cstdio>using namespace std;const int M=1001;long long dp[M][M],n,k,sum[M],a[M],cost[M][M],s[M][M];int main(){ while(s...原创 2018-02-25 21:40:50 · 165 阅读 · 0 评论 -
poj1180 Batch Scheduling
斜率优化裸体 很容易写出暴力dp dp[i]=min(dp[j]+(s+t[i]-t[j])*f[i])#include<cstdio>#include<iostream>double dp[11000],S,t[11000],f[11000];int head=1,tail=1,z[11000],n;double k(int x,int y){ r...原创 2018-02-25 20:04:42 · 181 阅读 · 0 评论 -
dp优化
单调队列优化 DP转移方程需要满足的条件:dp[i]=A(i)+B(j)中的最小/大值 (i-k<=j struct dddl//单调队列 { int q[maxn]; int p[maxn]; int h,t; void clear(){h=1,t=0;} void...原创 2018-02-25 11:01:12 · 300 阅读 · 0 评论 -
数位dp储能表
分解为二进制,有三个限制,每一位上每个限制是独立的,枚举记忆化搜索就行#include<iostream>#include<cstdio>#include<cstring>#define ll long long#define NODE pair<ll,ll>#define x first#define MP make_pair#d...原创 2018-03-10 11:29:19 · 229 阅读 · 0 评论 -
多重背包
单调队列优化,按理来说是均摊nm的 ,但t了然后我们知道标准的多重背包的dp转移方程为dp[i][j] = max{dp[i - 1][j - k * v[i]] + k * w[i]}然而你可以发现需要求最大值的对象有不少是重复的于是我们设v = v[i],a = j / v,b = j % v然后有dp[i][j] = max{dp[i - 1][b + k * v...原创 2018-02-22 20:47:31 · 189 阅读 · 0 评论 -
斜率优化题
[ZJOI 2007] 仓库建设 这里写链接内容DP[i]=min(DP[j]+c(i,j)+cost[i])DP[i]=min(DP[j]+(sum[i]−sum[j])∗x[i]−(sumxp[i]−sumxp[j])+cost[i]) 这种的式子可以斜率优化#include<cstdio>using namespace std;const int M=110...原创 2018-02-27 17:35:10 · 270 阅读 · 0 评论 -
尼克的任务
f[i]表示i-1以前的空暇时间最大 f[i+t]=max(f[i+t],f[i]) (一个是做这个任务,一个是不做) 先从第一个时间开始做,然后看做哪一个的空暇短 需要付最小值,因为你不能从后面的时间开始,必须前面推到过才行#include<cstdio>#include<iostream>#include<cstring>#include<vector>using namespac原创 2017-10-26 16:13:06 · 337 阅读 · 0 评论 -
跳舞
if(j(modt))!=0)f[i][j]=max(f[i−1][j−1]+a[i],f[i−1][j]−a[i]);elsef[i][j]=max(f[i−1][j−1]+a[i]+b[i],f[i−1][j]−a[i]); if(j \pmod t)! =0) f[i][j]=max(f[i-1][j-1]+a[i],f[i-1][j]-a[i]); else原创 2017-10-27 11:21:20 · 539 阅读 · 1 评论 -
拔河比赛
dp[j][k]=dp[j-1][k-w[i]#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<algorithm>using namespace std;bool dp[51][45000];int n,w[111],s;int main(){ scanf("%d",&n)原创 2017-08-10 17:06:13 · 570 阅读 · 0 评论 -
解药还是毒药
爆搜题 状态压缩 可以把要合并压缩为一个二进制数,1表示有病,0表示没病 分成两个数组 一个是治得a,一个是让他的病的b a中0表示治,1表示不治 b中0表示不得,1表示得 用a中的对他&就是治他了,因为只又全是一才不治有病的,不会影响到1 用b中的对他|就是让他患病,因为只要有一个是1,就患病,也不影响本来就患病的 举个例子 10110101 &00001001原创 2017-08-08 16:59:14 · 622 阅读 · 0 评论 -
过河(状压dp典型题)
这道题最简单的dp,动态转移方程很好推,因为它是由i-s~t转移来的,所 然而这个题的数据太大了。。。。。10^9 不得不考虑一些没用的操作 所以就考虑一个问题 这个题的石子数太少了,在一定的范围内,你不管怎样跳,石子数也不会增加,所以你就可以把多余的t弄掉,这样就是状压dp了,把一定的没用的范围压起来#include<cstdio>#include<iostream> #include原创 2017-06-06 18:03:58 · 517 阅读 · 0 评论 -
合唱队形(简单的动规)
#include<cstdio>#include<iostream>using namespace std;int m,n;int f[9999],f2[9999],h[9999]; int maxn=-9999;int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&h[i原创 2017-06-02 15:21:03 · 835 阅读 · 0 评论 -
最大正方形
dp 处理一个矩阵前缀和,就可以O(n)的求出矩阵的和了,而且只有和为完全平方数才是正方形,因为数据只有1吗,要是不是一的话就不容易了 这样再枚举一个起点,和一个边长就是任意一个正方形了,再优化剪枝一下,就可以0ms过了#include<cstdio>#include<iostream> using namespace std;int n,m;int maxn=1;int a[101][原创 2017-06-06 11:24:14 · 595 阅读 · 0 评论 -
方格取数or传纸条
用简单的搜索,之前听了从清北写的,一直没写博客,现在补上 这两个题实际上是一样的,传纸条虽然有一个是倒着传,其实和正着传是一样的,所以是一样的 就是用一个四维数组,记下两个点的坐标,两个点都可以向上或向下走,所以可以转移到四种情况,就是我下面分的四种 还可以用动归 动态转移方程是 dp[x][y][x2][y2]=max(dp[x][y-1][x2][y2-1],dp[x-1][y][x2原创 2017-06-06 09:20:01 · 314 阅读 · 0 评论 -
导弹拦截(数据加强版n<=300000)
普通的求一个最长上升子序列,一个最大下降子序列,输出就OK了,是n^2的复杂度 而这样就过不了300000的点了 所以我们就用二分查找的办法来优化,因为输入的复杂度无法优化,所以复杂度是nlogn 最长上升子序列上升思路: 有一个low数组,low[i]是长度为i的最长子序列的最小值 维护一个上升序列,如果加入的数>low[len],最长子序列就可以更新了,如果小于等于,则把正好大于他的一原创 2017-06-05 17:48:24 · 499 阅读 · 0 评论 -
01 背包找装满方案数 洛谷 p1164 小a点菜
#include<cstdio>using namespace std;int n,m;int f[9999];int a[9999];int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); f[0]=1; for(int i=1;i<=n;i++)原创 2016-12-21 15:57:25 · 490 阅读 · 0 评论 -
二维费用的背包
#include<cstdio>#include<cmath>#include<iostream>#include<cstring>using namespace std;int f[999][999];int m,n,k;int w[9999],c[9999],s[9999];int main(){ freopen("gas.in","r",stdin); fre原创 2016-12-14 16:00:40 · 283 阅读 · 0 评论 -
金明的预算方案(组合背包)
组合背包#include<iostream>using namespace std;int v[9999];int w[9999];int k[9999];int f[99999];int n,m;int t=0;int s[9999][10];int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) {原创 2017-02-08 11:36:46 · 270 阅读 · 0 评论 -
编辑距离(dp)
动态转移方程按三个步骤来,就是从f[i-1][j-1],f[i-1][j],f[i][j-1]+1转移过来 所以就是f[i][j]=min(f[i-1][j-1],f[i-1][j],f[i][j-1])+1#include<cstdio>#include<cstring> #include<iostream>using namespace std;char a[9999],b[9099]原创 2017-06-07 09:00:10 · 286 阅读 · 0 评论 -
乘积最大
简单的搜索#include<cstdio>#include<iostream>using namespace std;int k;int s[1999][1999],a[9999];int tot=-999;int m,n;int dfs(int x,int k,int ans,int j){ if(n-x<k)return 1; if(k==0) {原创 2017-06-02 17:53:25 · 439 阅读 · 0 评论 -
扫雷
某一位的状态可以由上面的和上上面的推过来 所以枚举第一位有没有雷 dp方程: b[i]=a[i-1]-b[i-2]-b[i-1];#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<stdlib.h>using namespace std;int n,a[19999],b[19999]原创 2017-08-08 15:28:02 · 200 阅读 · 0 评论 -
互不侵犯king
状压dp题 每一行放不放国王可以用1010010来表示 所以每一行的状态可以看成一个二进制数 这样n是小于9的,可以把小于2^n,(因为2^9是512,很小)的数打表存出来 把自己和自己冲突的筛掉,然后记下有多少1,判断他们是否冲突。 预处理完了,接下来是dp了 动态转移方程: dp[i][q+t[j]][a[j]]=Σdp[i-1][q][a[i]]#include<cstdio>原创 2017-08-08 11:19:25 · 279 阅读 · 0 评论 -
子串
这个题我搞了好久,终于算是明白了点吧 看了很多大神的博客,总结出来了一些做法,不知对不对,就写一些吧。 先定义两个数组 sum[i][j][k]就是a串前i个字母,b串前j个字母的方案总数!!!!,就是结果 f[i][j][k]是用第i个字母用的方案数。 因为第i个可以和前i-1合并为一块(但这是方案数不变,因为组数相同,为f[i-1][j-1][k]),也可以不合并,(为sum[i-1]原创 2017-06-11 17:18:48 · 202 阅读 · 0 评论 -
书的复制
这个题就是一个动归,和乘积最大一样,处理前缀和,枚举当前位置和划分层数,找最大的时间,取最小值#include<cstdio>#include<iostream>#include<cstring>using namespace std;int a[999999],f[3999][3999],m,n,s[999999];int print(int x,int y){ if(y==0)原创 2017-06-08 16:17:25 · 362 阅读 · 0 评论 -
最长上升子序列
最长公共子序列(lcs)到最长上升子序列(lis)的转化。 把第一个串的元素,转化为第二个串的位置,再倒过来,找最长上升子序列。 别问我为什么,我也不知道。。。。。#include<cstdio>#include<iostream>#include<cstring>#include<map>#define ll long longusing namespace std;int a[99原创 2017-06-08 15:34:56 · 308 阅读 · 0 评论 -
导弹拦截(1999noip)
求一个最长上升子序列,一个最大下降子序列,输出就OK了#include<cstdio>#include<iostream>#include<cstring> using namespace std;int m,n;int f[9999],f2[9999],h[9999]; int a[999];int maxn=-9999;int t;int j;int p;int u;int dfs原创 2017-06-04 11:30:06 · 355 阅读 · 0 评论 -
低价购买
第一问很好做,就是一个很简单的dp求最长下降子序列。 第二问就有一些问题了,怎么找最大的方案数呢? 那就需要看状态了,i位置的方案数只能由比他小一的位置转移过来,而且每一个都能转移过来,所以说 因为第一问求出f[i]了 所以递推方程式为 t[i]=∑t[j] (f[j]+1=f[i]) 但还有一个问题,不能重复,如果有相同的情况,就可以把后面的方案数去掉,因为不可能是最优解,这样就不重复原创 2017-06-07 17:20:23 · 232 阅读 · 0 评论 -
统计单词个数
这个题和之前一个乘法最大思路差不多,就是如果要划分k份之前已经划分了k-1份,划分为k份的就是由,k-1推来的再加上第k份的单词个数,所以就枚举前面k-1分到的位置,是k~当前位置,取最大值,就是结果了 然后单词个数就在线统计就行了,因为以一个数为首字母的只能用一次,所以找最短的单词记下来就行了。#include<cstdio>#include<cstring> #include<iostre原创 2017-06-07 11:18:01 · 393 阅读 · 0 评论