[kuangbin带你飞]专题十二 基础DP1 题解+总结
kuangbin带你飞:点击进入新世界
总结:
简单dp,最近在做,持续更新。
文章目录
- 总结:
- 1.Max Sum Plus Plus
- 2.Ignatius and the Princess IV
- 3.Monkey and Banana
- 4.最少拦截系统
- 5.Longest Ordered Subsequence
- 6.Common Subsequence
- 7.Super Jumping! Jumping! Jumping!
- 8.Milking Time
- 9.FatMouse and Cheese
- 10.Phalanx
- 11.FatMouse's Speed
- 12.免费馅饼
- 13.Tickets
1.Max Sum Plus Plus
原题链接:传送门
思路:
- 如果不看时间复杂度和空间复杂度的话,假设用2维dp来解决。
- dp[i][j]就是前j个数分成i组所取得的最大值,那么有:
- dp[i][j]=max(dp[i][j], dp[i][j]+a[j],dp[i-1][k]+a[j] ) k<i
- 前两个分别对应不取这个数和取这个数的情况(连续),第三个对应的是在前面取i-1组,在k处断开,然后a[j]为第i组。
- 但是1e6的数据范围导致时间和空间都不够,所以需要压缩,可以发现跟背包问题其实是相似的,如果用另外一个数组f[j]来表示dp[i-1][k]的情况,一维就放得下了。
- 代码可看注释。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e6+5;
int a[manx],dp[manx],f[manx];
int main()
{int n,m;while(scanf("%d%d",&m,&n)!=EOF) //数据较大,用scanf,不然会超时{for(int i=1;i<=n;i++)scanf("%d",&a[i]);int maxx;memset(dp,0,sizeof(dp));memset(f,0,sizeof(f));for(int i=1;i<=m;i++){maxx=-inf; for(int j=i;j<=n;j++) //分成i组的话那么必须从i开始{dp[j]=max(dp[j-1]+a[j],f[j-1]+a[j]);//f[j-1]是前面j-1个数取i-1组的最大值//dp[j-1]是前面j-1个数取i组的最大值//那么dp[j]就是j个数分i组的最大值f[j-1]=maxx; //这里j-1是因为maxx是上个循环得到的,就是前面dp[j-1]和maxx的较大值maxx=max(dp[j],maxx);//假设当前是循环到i组的时候,这个f数组是会在i+1组的时候用到}}printf("%d\n",maxx);}return 0;
}
2.Ignatius and the Princess IV
原题链接:传送门
思路:
- 跟dp好像没什么关系,用一个map计数即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e6+5;
int a[manx];
map<int,int>mp;
int main()
{int n;while(scanf("%d",&n)!=EOF){mp.clear();for(int i=1;i<=n;i++){scanf("%d",&a[i]);mp[a[i]]++;}for(int i=1;i<=n;i++)if(mp[a[i]]>=(n+1)/2){printf("%d\n",a[i]);break;}}return 0;
}
3.Monkey and Banana
原题链接:传送门
思路:
- 求最大子序列和,不过附加了一些其他条件:
- 后续的长和宽必须小于前面的
- 这题主要是输入的时候把六种情况都存进去就可以了。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1000;
int dp[manx];
struct node{int l,r,w;
}a[manx];
bool cmp(node a,node b){if(a.l==b.l) return a.r<b.r;return a.l<b.l;
}
int main()
{int n,t=1;while(scanf("%d",&n)!=EOF){if(!n) break;int index=1;for(int i=1;i<=n;i++){int l,r,w;scanf("%d%d%d",&l,&r,&w);a[index].l=l,a[index].r=r,a[index++].w=w;a[index].l=l,a[index].r=w,a[index++].w=r;a[index].l=r,a[index].r=l,a[index++].w=w;a[index].l=r,a[index].r=w,a[index++].w=l;a[index].l=w,a[index].r=l,a[index++].w=r;a[index].l=w,a[index].r=r,a[index++].w=l;}sort(a+1,a+1+index,cmp);memset(dp,0,sizeof(dp));int ans=0;for(int i=1;i<index-1;i++){for(int j=i;j<index;j++)if(a[i].l<a[j].l&&a[i].r<a[j].r)dp[j]=max(dp[j],dp[i]+a[j].w),ans=max(ans,dp[j]);}cout<<"Case "<<t++<<": maximum height = "<<ans<<endl;}return 0;
}
4.最少拦截系统
原题链接:传送门
思路:
- LIS模板题,很经典的DP。
- dp[i]表示前i个至少需要的导弹数。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e6+5;
int a[manx],dp[manx];
int main()
{int n,t=1;while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++)scanf("%d",&a[i]),dp[i]=1;int ans=0;for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++)if(a[j]>a[i])dp[j]=max(dp[i]+1,dp[j]);ans=max(ans,dp[i]);}cout<<ans<<endl;}return 0;
}
5.Longest Ordered Subsequence
原题链接:传送门
思路:
- 最长上升子序列,跟上面那一题相同。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e6+5;
int a[manx],dp[manx];
int main()
{int n,t=1;while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++)scanf("%d",&a[i]),dp[i]=1;int ans=0;for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++)if(a[j]>a[i])dp[j]=max(dp[i]+1,dp[j]);ans=max(ans,dp[i]);}cout<<ans<<endl;}return 0;
}
6.Common Subsequence
原题链接:传送门
思路:
- 最长相同子序列,dp[i][j]是第一个串的前i个和第二个串的前j个最大相同序列长度数。
- 由第一个开始递推,dp[n][m]就是答案。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e3+5;
string s1,s2;
int dp[manx][manx];
int main()
{int n,t=1;while(scanf("%s%s",&s1,&s2)!=EOF){memset(dp,0,sizeof(dp));for(int i=1;i<=s1.size();i++)for(int j=1;j<=s2.size();j++)if(s1[i-1]==s2[j-1])dp[i][j]=dp[i-1][j-1]+1;elsedp[i][j]=max(dp[i-1][j],dp[i][j-1]);cout<<dp[s1.size()][s2.size()]<<endl;}return 0;
}
7.Super Jumping! Jumping! Jumping!
原题链接:传送门
思路:
- 最大递增子序列的序列和。
- dp[i]为前i个数中的最大值。
- 把dp[i]初始化为a[i]
- 那么dp[i]=max(dp[i],dp[k]+a[k]) when k<i&&a[k]<a[i]
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e3+5;
int dp[manx];
int a[manx];
int main()
{int n,t=1;while(scanf("%d",&n)!=EOF){if(!n) break;memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++)scanf("%d",&a[i]),dp[i]=a[i];int ans=0;for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++)if(a[j]>a[i])dp[j]=max(dp[j],dp[i]+a[j]);ans=max(ans,dp[i]);}cout<<ans<<endl;}return 0;
}
8.Milking Time
原题链接:传送门
思路:
- dp[i]日常表示前i个数的最大价值。
- 这题主要是把数据处理一下,把结束时间加上r,然后记得把结构体排序。
- 那么就转化成一维的最大子序列和了。
- dp[i]=max(dp[i],dp[k]+a[j].w) when a[k].r<=a[i].l&&l>k
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e3+5;
int dp[manx];
struct node{int l,r,w;
}a[manx];
bool cmp(node a,node b){return a.l<b.l;
}
int main()
{int n,m,r,t=1;while(scanf("%d%d%d",&n,&m,&r)!=EOF){for(int i=1;i<=m;i++){cin>>a[i].l>>a[i].r>>a[i].w;a[i].r+=r;}sort(a+1,a+1+m,cmp);int ans=0;for(int i=1;i<=m;i++)dp[i]=a[i].w;for(int i=1;i<=m;i++){for(int j=i+1;j<=m;j++)if(a[j].l>=a[i].r)dp[j]=max(dp[j],dp[i]+a[j].w);ans=max(ans,dp[i]);}cout<<ans<<endl;}return 0;
}
9.FatMouse and Cheese
原题链接:传送门
思路:
- 这道题的话,跟地图相关,搜索是必须的。
- 放在dp专题里面,无非就是记忆化搜索,注意最后return 。
- dp[x][y]=a[x][y]+mx
- mx为这个点开始往后搜索得到的最大值。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=2e3+5;
int dp[manx][manx],a[manx][manx];
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};
int n,m,r,t=1;
int dfs(int x,int y){if(dp[x][y]) return dp[x][y];int mx=0;for(int i=1;i<=m;i++){for(int j=0;j<4;j++){int xx=x+dx[j]*i,yy=y+dy[j]*i;if(a[x][y]<a[xx][yy]&&xx>0&&yy>0&&xx<=n&&yy<=n)mx=max(dfs(xx,yy),mx);}}return dp[x][y]=a[x][y]+mx;
}
int main()
{while(scanf("%d%d",&n,&m)!=EOF){if(n==-1&&m==-1) break;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>a[i][j];memset(dp,0,sizeof(dp));cout<< dfs(1,1)<<endl;}return 0;
}
10.Phalanx
原题链接:传送门
思路:
- 最大对称子矩阵,左下角到右上角为对称轴。
- 枚举每一个点,如果相同,把行数x向上扩展,列数y相右扩展。
- dp[i][j]=min(dp[i-1][j+1],i-x-1)+1 when c[i][j+1]==c[i-1][j]
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=2e3+5;
int dp[manx][manx];
char c[manx][manx];
int n,m,r,t=1;
int main()
{while(scanf("%d",&n)!=EOF){if(!n) break;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>c[i][j];memset(dp,0,sizeof(dp));int ans=1;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){dp[i][j]=1;int x=i,y=j;while(c[i][y]==c[x][j]) x--,y++;if(c[i][j+1]==c[i-1][j])dp[i][j]=min(dp[i-1][j+1],i-x-1)+1;ans=max(ans,dp[i][j]);}cout<<ans<<endl;}return 0;
}
11.FatMouse’s Speed
原题链接:传送门
思路:
- 输入保存一下数据,然后排个序,就是简单的最长xx子序列。
- 因为后面需要输出路径,所以在枚举的时候可以逆向枚举i,再从后面往前面更新,这样输出的时候就可以根据ans的值来进行输出。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=2e3+5;
int dp[manx],q[manx];
struct node {int w,v,x;
}a[manx];
bool cmp(node a,node b){if(a.w==b.w) return a.v>b.v;return a.w<b.w;
}
int n,m,r,t=0;
int main()
{while(scanf("%d%d",&n,&m)!=EOF){a[++t].w=n,a[t].v=m,a[t].x=t;}sort(a+1,a+t+1,cmp);int ans=0;for(int i=t;i>=1;i--){dp[i]=1;for(int j=i+1;j<=t;j++)if(a[j].w>a[i].w&&a[j].v<a[i].v)dp[i]=max(dp[j]+1,dp[i]);ans=max(dp[i],ans);}cout<<ans<<endl;for(int i=1;i<=t;i++){if(dp[i]==ans)cout<<a[i].x<<endl,ans--;}return 0;
}
12.免费馅饼
原题链接:传送门
思路:
- 如果把时间轴看成行数,每个点在这个时间上获得的饼数看成列数,那么a[i][j]表示在时间为i时j点获得的饼,如果把图画出来就可以发现这其实是一道数塔题。
- 因为要处理相邻两边,下标为0的时候不好处理,所以把位置+1;
- 既然是数塔题,那么显而易见:
- dp[i][j]=max( dp[i+1][j-1] , dp[i+1][j] , dp[i+1][j+1] )
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=1e5+5;
int dp[manx][15];
int a[manx][15];
int n,m,r,t=0;
int main()
{while(scanf("%d",&n)!=EOF){if(!n) break;memset(dp,0,sizeof(dp));memset(a,0,sizeof(a));int e=0;for(int i=1;i<=n;i++){int x,t;scanf("%d%d",&x,&t);a[t][++x]++;e=max(e,t);}for(int i=e;i>=0;i--)for(int j=1;j<=11;j++)dp[i][j]=max(dp[i+1][j-1],max(dp[i+1][j],dp[i+1][j+1]))+a[i][j];printf("%d\n",dp[0][6]);}return 0;
}
13.Tickets
原题链接:传送门
思路:
- 只能两个人一起买票,那么递推式很容易推出来:
- dp[i]=min(dp[i-1]+a[i] , dp[j-2]+b[i])
- 此处为单独买,和前一个人的买的较大值
- dp[n]为答案 。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#define ll unsigned long long
#define inf 1<<30
using namespace std;
const int manx=2e3+5;
int a[manx],b[manx],dp[manx];
int n,m,r,t=0;
int main()
{while(scanf("%d",&t)!=EOF){while(t--){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=2;i<=n;i++) cin>>b[i];dp[1]=a[1];for(int i=2;i<=n;i++)dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i]);int h=8,mi=0,sec=0;sec+=dp[n];mi+=sec/60%60;h+=sec/3600;sec%=60;printf("%02d:%02d:%02d ",h,mi,sec);if(h>=12) printf("pm\n");else printf("am\n");}}return 0;
}
[kuangbin带你飞]专题十二 基础DP1 题解+总结相关推荐
- [kuangbin带你飞]专题十二 基础DP1
A - Max Sum Plus Plus (HDU 1024) 题意:将n个数取m段且不相交,求m段数字和最大值: dp[i][j]:前i个数字分成j段的最大值. 边界dp[0][0] = 0; d ...
- [kuangbin带你飞]专题十二 基础DP1 C - Monkey and Banana HDU - 1069
C - Monkey and Banana HDU - 1069 题目链接:https://vjudge.net/contest/68966#problem/C 题目: A group of rese ...
- [kuangbin带你飞]专题五 并查集 题解+总结
kuangbin带你飞:点击进入新世界 总结: 本人算是初学者中的初学者,欢迎交流~ 并查集的接触过的不多,大概只有普通并查集,带权并查集,种族并查集,传说中的可持续化并查集只是听说过还没有接触,不过 ...
- [kuangbin带你飞]专题十四 数论基础
A - Bi-shoe and Phi-shoe --筛素数 题意 一个竹竿长度为p,它的score值就是比p长度小且与且与p互质的数字总数,比如9有1,2,4,5,7,8这六个数那它的score就是 ...
- kuangbin带你飞专题合集
题目列表 [kuangbin带你飞]专题一 简单搜索 [kuangbin带你飞]专题二 搜索进阶 [kuangbin带你飞]专题三 Dancing Links [kuangbin带你飞]专题四 最短路 ...
- kuangbin带你飞 专题1-23 题单
kuangbin大神,对于打过ACM比赛的ACMer,无人不知无人不晓. 在此,附上vjudge平台上一位大神整理的[kuangbin带你飞]专题目录链接. [kuangbin带你飞专题目录1-23] ...
- “kuangbin带你飞”专题计划——专题十四:数论基础
写在前面 1.目前还没啥写的.开始时间:2021-05-13(其实博客上看得到该博客创建时间的) 2.上一个专题刷的是网络流(博客总结),属于第一次接触.本来想的是一周特别高效,然后一周略划水,结果是 ...
- kuangbin专题十二 基础DP
kuangbin专题十二 基础DP A - HDU1024 Max Sum Plus Plus B - HDU1029 Ignatius and the Princess IV C - HDU1069 ...
- (2021-07-14~)“kuangbin带你飞”专题计划——专题十三:基础计算几何
目录 前言 参考博客 自己总结的东西: 难度判断? 题目 1.[TOYS POJ - 2318 ](解决) 2.[Toy Storage POJ - 2398 ](解决) 3.[Segments PO ...
最新文章
- CSS选择器的声明与嵌套
- gRPC 基础概念详解
- 小程序测试用例模板_微信小程序样式:高质量小程序样式模板大全
- Tomcat下载与安装
- Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。
- C++ 模板双向不循环链表!!
- 行尸走肉第八季/全集The Walking Dead迅雷下载
- 汉字--拼音--网页汉字转拼音--包教包会
- bt种子制作php,BT种子制作
- 主机防火墙与访问控制
- matlab粒子群运动模拟伪代码,基本粒子群优化算法(PSO)的matlab实现
- 如何判断一个PCIe的capability是哪个capability
- wuauclt.exe出错?self.bat,abopx.sys等作怪
- 哈迪-温伯格平衡(Hardy-Weinberg equilibrium)法则
- js获取视频长度的3种方法
- python小白到大牛pdf_清华大学出版《python小白到大牛》PDF版分享
- 龙书虎书鲸书啃不动?试试豆瓣评分9.5的猴书
- BT profile
- 图像处理与计算机视觉网址导航
- 解决win10分辨率过高导致某些软件显示小的办法: