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

原题链接:传送门

思路:

  1. 如果不看时间复杂度和空间复杂度的话,假设用2维dp来解决。
  2. dp[i][j]就是前j个数分成i组所取得的最大值,那么有:
  3. dp[i][j]=max(dp[i][j], dp[i][j]+a[j],dp[i-1][k]+a[j] ) k<i
  4. 前两个分别对应不取这个数和取这个数的情况(连续),第三个对应的是在前面取i-1组,在k处断开,然后a[j]为第i组。
  5. 但是1e6的数据范围导致时间和空间都不够,所以需要压缩,可以发现跟背包问题其实是相似的,如果用另外一个数组f[j]来表示dp[i-1][k]的情况,一维就放得下了。
  6. 代码可看注释。

    代码如下:

#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

原题链接:传送门

思路:

  1. 跟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

原题链接:传送门

思路:

  1. 求最大子序列和,不过附加了一些其他条件:
  2. 后续的长和宽必须小于前面的
  3. 这题主要是输入的时候把六种情况都存进去就可以了。

    代码如下:

#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.最少拦截系统

原题链接:传送门

思路:

  1. LIS模板题,很经典的DP。
  2. 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

原题链接:传送门

思路:

  1. 最长上升子序列,跟上面那一题相同。

    代码如下:

#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

原题链接:传送门

思路:

  1. 最长相同子序列,dp[i][j]是第一个串的前i个和第二个串的前j个最大相同序列长度数。
  2. 由第一个开始递推,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!

原题链接:传送门

思路:

  1. 最大递增子序列的序列和。
  2. dp[i]为前i个数中的最大值。
  3. 把dp[i]初始化为a[i]
  4. 那么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

原题链接:传送门

思路:

  1. dp[i]日常表示前i个数的最大价值。
  2. 这题主要是把数据处理一下,把结束时间加上r,然后记得把结构体排序。
  3. 那么就转化成一维的最大子序列和了。
  4. 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

原题链接:传送门

思路:

  1. 这道题的话,跟地图相关,搜索是必须的。
  2. 放在dp专题里面,无非就是记忆化搜索,注意最后return 。
  3. dp[x][y]=a[x][y]+mx
  4. 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

原题链接:传送门

思路:

  1. 最大对称子矩阵,左下角到右上角为对称轴。
  2. 枚举每一个点,如果相同,把行数x向上扩展,列数y相右扩展。
  3. 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

原题链接:传送门

思路:

  1. 输入保存一下数据,然后排个序,就是简单的最长xx子序列。
  2. 因为后面需要输出路径,所以在枚举的时候可以逆向枚举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.免费馅饼

原题链接:传送门

思路:

  1. 如果把时间轴看成行数,每个点在这个时间上获得的饼数看成列数,那么a[i][j]表示在时间为i时j点获得的饼,如果把图画出来就可以发现这其实是一道数塔题。
  2. 因为要处理相邻两边,下标为0的时候不好处理,所以把位置+1;
  3. 既然是数塔题,那么显而易见:
  4. 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

原题链接:传送门

思路:

  1. 只能两个人一起买票,那么递推式很容易推出来:
  2. dp[i]=min(dp[i-1]+a[i] , dp[j-2]+b[i])
  3. 此处为单独买,和前一个人的买的较大值
  4. 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 题解+总结相关推荐

  1. [kuangbin带你飞]专题十二 基础DP1

    A - Max Sum Plus Plus (HDU 1024) 题意:将n个数取m段且不相交,求m段数字和最大值: dp[i][j]:前i个数字分成j段的最大值. 边界dp[0][0] = 0; d ...

  2. [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 ...

  3. [kuangbin带你飞]专题五 并查集 题解+总结

    kuangbin带你飞:点击进入新世界 总结: 本人算是初学者中的初学者,欢迎交流~ 并查集的接触过的不多,大概只有普通并查集,带权并查集,种族并查集,传说中的可持续化并查集只是听说过还没有接触,不过 ...

  4. [kuangbin带你飞]专题十四 数论基础

    A - Bi-shoe and Phi-shoe --筛素数 题意 一个竹竿长度为p,它的score值就是比p长度小且与且与p互质的数字总数,比如9有1,2,4,5,7,8这六个数那它的score就是 ...

  5. kuangbin带你飞专题合集

    题目列表 [kuangbin带你飞]专题一 简单搜索 [kuangbin带你飞]专题二 搜索进阶 [kuangbin带你飞]专题三 Dancing Links [kuangbin带你飞]专题四 最短路 ...

  6. kuangbin带你飞 专题1-23 题单

    kuangbin大神,对于打过ACM比赛的ACMer,无人不知无人不晓. 在此,附上vjudge平台上一位大神整理的[kuangbin带你飞]专题目录链接. [kuangbin带你飞专题目录1-23] ...

  7. “kuangbin带你飞”专题计划——专题十四:数论基础

    写在前面 1.目前还没啥写的.开始时间:2021-05-13(其实博客上看得到该博客创建时间的) 2.上一个专题刷的是网络流(博客总结),属于第一次接触.本来想的是一周特别高效,然后一周略划水,结果是 ...

  8. kuangbin专题十二 基础DP

    kuangbin专题十二 基础DP A - HDU1024 Max Sum Plus Plus B - HDU1029 Ignatius and the Princess IV C - HDU1069 ...

  9. (2021-07-14~)“kuangbin带你飞”专题计划——专题十三:基础计算几何

    目录 前言 参考博客 自己总结的东西: 难度判断? 题目 1.[TOYS POJ - 2318 ](解决) 2.[Toy Storage POJ - 2398 ](解决) 3.[Segments PO ...

最新文章

  1. CSS选择器的声明与嵌套
  2. gRPC 基础概念详解
  3. 小程序测试用例模板_微信小程序样式:高质量小程序样式模板大全
  4. Tomcat下载与安装
  5. Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。
  6. C++ 模板双向不循环链表!!
  7. 行尸走肉第八季/全集The Walking Dead迅雷下载
  8. 汉字--拼音--网页汉字转拼音--包教包会
  9. bt种子制作php,BT种子制作
  10. 主机防火墙与访问控制
  11. matlab粒子群运动模拟伪代码,基本粒子群优化算法(PSO)的matlab实现
  12. 如何判断一个PCIe的capability是哪个capability
  13. wuauclt.exe出错?self.bat,abopx.sys等作怪
  14. 哈迪-温伯格平衡(Hardy-Weinberg equilibrium)法则
  15. js获取视频长度的3种方法
  16. python小白到大牛pdf_清华大学出版《python小白到大牛》PDF版分享
  17. 龙书虎书鲸书啃不动?试试豆瓣评分9.5的猴书
  18. BT profile
  19. 图像处理与计算机视觉网址导航
  20. 解决win10分辨率过高导致某些软件显示小的办法:

热门文章

  1. 欧拉如何解决哥尼斯堡七桥问题(二)
  2. 游戏3D美术设计师前景怎么样?
  3. web前端布局篇(切图)
  4. [《关于外婆家的一些记忆》闲笔记事集]2012年1月22日
  5. 旋转矩阵,矩阵,共轭矩阵
  6. Linux查询一个进程是被那个启动项启动的
  7. GprMax2D ——英国建筑研究机构(BRE)示例 #2
  8. android手机扇区数据读写,磁盘、SD卡、移动磁盘物理扇区读写
  9. Android GPS根据经度获取时区
  10. Mac电脑装centos虚拟机网络设置