简单暴力到dp的优化(中级篇)

下面再放三道我比较喜欢的,需要好好写一下的题。

第一题比较水

1. White Cloud is exercising in the playground. White Cloud can walk 1 meters or run k meters per second. Since White Cloud is tired,it can't run for two or more continuous seconds. White Cloud will move L to R meters. It wants to know how many different ways there are to achieve its goal. Two ways are different if and only if they move different meters or spend different seconds or in one second, one of them walks and the other runs.

输入描述: The first line of input contains 2 integers Q and k.Q is the number of queries.(Q<=100000,1<=k<=100000) For the next Q lines,each line contains two integers L and R.(1<=L<=R<=100000)

输出描述: For each query,print a line which contains an integer,denoting the answer of the query modulo 1000000007.

示例1: 输入 3 3 3 3 1 4 1 5 输出 2 7 11

题目大意

白云在健身,每秒可以走1米或跑k米,并且不能连续两秒都在跑。 当它的移动距离在[L,R]之间时,可以选择结束锻炼。 问有多少种方案结束。

做法

DP? f[i][0/1]表示已经过了i米,最后一步是跑还是走的方案数,分开就很好写了,简单,自己体会。 f[i][1]=f[i-k][0],f[i][0]=f[i-1][0]+f[i-1][1] 注意要记录前缀和。

 

#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
typedef long long ll;
ll g[100005];
ll dp[100005][2];
int main(void)
{int q,k,a,b;ll sum;cin>>q>>k;dp[0][0]=1;for(int i=1;i<=100000;++i){dp[i][0]=(dp[i-1][0]+dp[i-1][1])%MOD;if(i-k>=0)dp[i][1]=(dp[i-k][0])%MOD;}sum=0;for(int i=1;i<=100000;++i){g[i]=(dp[i][0]+dp[i][1]+sum);sum=g[i];}// for(int i=9000;i<=100000;++i){//     cout<<g[i]<<endl;// }while(q--){cin>>a>>b;cout<<(g[b]-g[a-1])%MOD<<endl;}return 0;
}

 

2、来一发多重背包

选这个题是感觉代码有一种美感。。。。。

一. 编程题

1. Since then on, Eddy found that physics is actually the most important thing in the contest. Thus, he wants to form a team to guide the following contestants to conquer the PACM contests(PACM is short for Physics, Algorithm, Coding, Math).

There are N candidate groups each composed of pi physics experts, ai algorithm experts, ci coding experts, mi math experts. For each group, Eddy can either invite all of them or none of them. If i-th team is invited, they will bring gi knowledge points which is calculated by Eddy's magic formula. Eddy believes that the higher the total knowledge points is, the better a team could place in a contest. But, Eddy doesn't want too many experts in the same area in the invited groups. Thus, the number of invited physics experts should not exceed P, and A for algorithm experts, C for coding experts, M for math experts.

Eddy is still busy in studying Physics. You come to help him to figure out which groups should be invited such that they doesn't exceed the constraint and will bring the most knowledge points in total.

输入描述: The first line contains a positive integer N indicating the number of candidate groups. Each of following N lines contains five space-separated integer p i, ai, ci, mi, gi indicating that i-th team consists of pi physics experts, ai algorithm experts, ci coding experts, mi math experts, and will bring gi knowledge points. The last line contains four space-separated integer P, A, C, M indicating the maximum possible number of physics experts, algorithm experts, coding experts, and math experts, respectively.

 1 ≤ N ≤ 36 0 ≤ pi,ai,ci,mi,gi ≤ 36 0 ≤ P, A, C, M ≤ 36

输出描述: The first line should contain a non-negative integer K indicating the number of invited groups. The second line should contain K space-separated integer indicating the index of invited groups(groups are indexed from 0).

You can output index in any order as long as each index appears at most once. If there are multiple way to reach the most total knowledge points, you can output any one of them. If none of the groups will be invited, you could either output one line or output a blank line in the second line.

题干有点长,其实就是每个队有四种代价,一个价值。多重背包。36的五次方竟然没超时也是醉了。。

 

#include <bits/stdc++.h>
using namespace std;
const int N=37;
int n, p[N], a[N], c[N], m[N], g[N];
int P, A, C, M;
short dp[N][N][N][N][N];
bool tk[N][N][N][N][N];
int main(){cin>>n;for(int i=0; i<n; i++)cin>>p[i]>>a[i]>>c[i]>>m[i]>>g[i];cin>>P>>A>>C>>M;for(int i=0; i<=n; i++)for(int ip=0; ip<=P; ip++)for(int ia=0; ia<=A; ia++)for(int ic=0; ic<=C; ic++)for(int im=0; im<=M; im++)tk[i][ip][ia][ic][im]=false;for(int i=0; i<n; i++){for(int ip=P; ip>=0; ip--)for(int ia=A; ia>=0; ia--)for(int ic=C; ic>=0; ic--)for(int im=M; im>=0; im--)dp[i+1][ip][ia][ic][im]=dp[i][ip][ia][ic][im];for(int ip=P; ip>=p[i]; ip--)for(int ia=A; ia>=a[i]; ia--)for(int ic=C; ic>=c[i]; ic--)for(int im=M; im>=m[i]; im--)if(dp[i][ip-p[i]][ia-a[i]][ic-c[i]][im-m[i]]+g[i]>dp[i+1][ip][ia][ic][im]){dp[i+1][ip][ia][ic][im]=dp[i][ip-p[i]][ia-a[i]][ic-c[i]][im-m[i]]+g[i];tk[i+1][ip][ia][ic][im]=true;}}fprintf(stderr, "ans=%d\n", dp[n][P][A][C][M]);vector<int> ans;for(int i=n; i>=1; i--)if(tk[i][P][A][C][M]){ans.push_back(i-1);P-=p[i-1];A-=a[i-1];C-=c[i-1];M-=m[i-1];}reverse(ans.begin(), ans.end());printf("%d\n", (int)ans.size());for(size_t i=0; i<ans.size(); i++)printf("%d%c", ans[i], " \n"[i+1==ans.size()]);
}

3、P1040 加分二叉树

题目

https://www.luogu.org/problemnew/show/P1040

设一个 nn 个节点的二叉树tree的中序遍历为( 1,2,3,…,n1,2,3,…,n ),其中数字 1,2,3,…,n1,2,3,…,n 为节点编号。每个节点都有一个分数(均为正整数),记第 ii 个节点的分数为 di,treedi,tree 及它的每个子树都有一个加分,任一棵子树 subtreesubtree (也包含 treetree 本身)的加分计算方法如下:

subtreesubtree 的左子树的加分× subtreesubtree 的右子树的加分+ subtreesubtree 的根的分数。

若某个子树为空,规定其加分为 11 ,叶子的加分就是叶节点本身的分数。不考虑它的空子树。

试求一棵符合中序遍历为( 1,2,3,…,n1,2,3,…,n )且加分最高的二叉树 treetree 。要求输出;

(1) treetree 的最高加分

(2) treetree 的前序遍历

思路:这个题可以用动态规划或者记忆化搜索来做。因为如果要求加分最大的话,必须要求它的儿子结点加分最大,所以就有了最优子阶段。我们可以枚举根来更新最大值。

root[i,j]表示[i,j]这段序列的根,递归输出先序遍历。注意初始化,f[i][i]=v[i],当序列只有I一个元素时,f[i][i]等于这个点本身的权值,当l==r-1时,此时是空树设为1。

 

#include<iostream>
#include<cstdio>
using namespace std;
int n,v[39],f[47][47],i,j,k,root[49][49];
void print(int l,int r){if(l>r)return;if(l==r){printf("%d ",l);return;}printf("%d ",root[l][r]);print(l,root[l][r]-1);print(root[l][r]+1,r);
}
int main() {scanf("%d",&n);for( i=1; i<=n; i++) scanf("%d",&v[i]);for(i=1; i<=n; i++) {f[i][i]=v[i];f[i][i-1]=1;}for(i=n; i>=1; i--)for(j=i+1; j<=n; j++)for(k=i; k<=j; k++) {if(f[i][j]<(f[i][k-1]*f[k+1][j]+f[k][k])) {f[i][j]=f[i][k-1]*f[k+1][j]+f[k][k];root[i][j]=k;}}printf("%d\n",f[1][n]);print(1,n);return 0;
}

 

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/445662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第二次课 课上代码

敲一遍&#xff0c;体会每行代码想表达的意思。 第二讲 创建.py文件 数据类型&#xff1a;布尔(and\or\not) 条件判断语句(if elif else) 列表基础操作&#xff08;特点、创建、增加元素、len()、下标、py切片&#xff09; >>> 5>4 True >>> 4>5 Fa…

第一次课 优秀作业展示

18级河北师大软件编程训练 很多同学非常认真的完成了作业&#xff0c;这里选出比较优秀的作业展示出来。 注&#xff1a;展示顺序不是排名 为了尊重同学们的劳动成果&#xff0c;并没有要代码&#xff0c;只是截图展示。 范天祚 &#xff08;傻兔子&#xff09; 熊静祎&…

dp打开思路:HDU1029 HDU1087 HDU1176 HDU1257 POJ1458(水题不水)

题目&#xff1a;https://vjudge.net/contest/68966#overview HDU - 1029 题意&#xff1a;找出出现次数超过一半的数字 蠢思路&#xff1a;排序找中间 DP&#xff1a;扫一遍一个变量count记录解出现的次数&#xff0c;是当前解就&#xff0c;否则--&#xff0c;count为负就…

dp打开思路2:POJ2533 HDU1114 HDU1260 HDU1160(水题不水)

题目&#xff1a;https://vjudge.net/contest/68966#overview POJ2533 最长上升子序列&#xff0c;很平常的题&#xff0c;但是维持单调队列二分还是值得一贴的&#xff0c;O(nlogn) 关键思想&#xff1a;出现在单调队列里的数都在当前接收的数之前&#xff0c;所以找到最小…

二分查找及一般拓展总结

二分-不止是查找哦 二分过程&#xff1a;首先&#xff0c;假设表中元素是按升序排列&#xff0c;将表中间位置记录的关键字与查找关键字比较&#xff0c;如果两者相等&#xff0c;则查找成功&#xff1b;否则利用中间位置记录将表分成前、后两个子表&#xff0c;如果中间位置记…

第三次课 课上代码

这次可能比较简短&#xff0c;这样也好&#xff0c;可读性比较强。 别问我为什么&#xff0c;我不会告诉你们我把代码关了的哼哼。 简单复习、注意事项及小知识强调讲解 作业讲解 列表的遍历 For循环&#xff08;这个参考切片&#xff0c;视频有详细讲解&#xff0c;一样的…

排序算法基本介绍及python实现(含详细注释)

对数组排序可以说是编程基础中的基础&#xff0c;本文对八种排序方法做简要介绍并用python实现。 代码中注释很全&#xff0c;适合复习和萌新学习。这是刚入学自己写的&#xff0c;可能难免比不上标准的写法&#xff0c;但是懒得改了。 文末会放和排序相关的基本拓展总结链接…

第二次作业 讲解及展示

第二次作业&#xff0c;同学们虽然在认真完成&#xff0c;但是或多或少都出了一些错误&#xff0c;一班张婷&#xff0c;四班武仪人&#xff0c;六班杨泽宇&#xff0c;八班候雯洁&#xff0c;安锦阳&#xff0c;刘净圆&#xff0c;这些同学完成的较为出色&#xff0c;错误较少…

深搜DFS\广搜BFS 图初步入门

首先&#xff0c;不管是BFS还是DFS&#xff0c;由于时间和空间的局限性&#xff0c;它们只能解决数据量比较小的问题。 深搜&#xff0c;顾名思义&#xff0c;它从某个状态开始&#xff0c;不断的转移状态&#xff0c;直到无法转移&#xff0c;然后退回到上一步的状态&#xf…

素数基本(埃氏筛法/线性筛法)

一、检查n是否为素数 最简单思路&#xff1a;所有可能的因数全部试一遍。 int gg(int n) {for(int i2;i<n;i){if((n%i)0)return 0;//有因数就不是素数咯}return 1; } 进一步思考&#xff1a;没必要枚举所有的数&#xff0c;每一个小于n^(1/2)的因数i&#xff0c;一定有一个大…

欧几里得gcd/extend_gcd

正式叙述前还写了一点自己的小感受。 问题&#xff1a;求两个正整数a&#xff0c;b的最大公约数。 大神看来是很简单的问题&#xff0c;但是对于去年夏天刚学python的我来说&#xff0c;这是个很难的问题&#xff0c;还记得当时一晚上睡不着都在想怎么快一点的求出最大公约数…

python基础技巧总结(一)

最近总结一下python基础知识&#xff0c;就暂时弃坑了。 本文总结只属于python的一些骚操作。。。 后面文章自行去博客学习交流 原地交换 Python 提供了一个直观的在一行代码中赋值与交换&#xff08;变量值&#xff09;的方法 x, y 10, 20 print(x, y)x, y y, x print(x…

python基础技巧总结(二)

一总结的链接&#xff1a; 好&#xff0c;我们继续 一次性初始化多个变量 可以直接赋值&#xff1a; a,b,c,d1,2,3,4 可以利用列表&#xff1a; List [1,2,3] x,y,zList print(x, y, z) #-> 1 2 3 &#xff08;元素个数应与列表长度相同&#xff09; 打印模块路径 im…

python基础技巧总结(三)

前两篇文章&#xff1a; https://blog.csdn.net/hebtu666/article/details/81698235 https://blog.csdn.net/hebtu666/article/details/81698329 我们继续总结&#xff1a; 开启文件分享 Python 允许运行一个 HTTP 服务器来从根路径共享文件&#xff0c;下面是开启服务器的…

python基础技巧总结(四)

前三期请到我博客里找 https://blog.csdn.net/hebtu666 我们继续总结 except的用法和作用 try/except: 捕捉由PYTHON自身或写程序过程中引发的异常并恢复 except: 捕捉所有其他异常 except name: 只捕捉特定的异常 except name, value: 捕捉异常及格外的数据(实例) exce…

python基础技巧总结(五)

前四期到博客找&#xff1a;https://blog.csdn.net/hebtu666 我们继续说一些好用的函数 split Python split() 通过指定分隔符对字符串进行切片&#xff0c;如果参数 num 有指定值&#xff0c;则仅分隔 num 个子字符串。 语法&#xff1a; str.split(str"", num…

堆的简单实现

关于堆不做过多介绍 堆就是儿子的值一定不小于父亲的值并且树的节点都是按照从上到下&#xff0c;从左到右紧凑排列的树。 &#xff08;本文为二叉堆&#xff09; 具体实现并不需要指针二叉树&#xff0c;用数组储存并且利用公式找到父子即可。 父&#xff1a;(i-1)/2 子:…

二叉搜索树实现

本文给出二叉搜索树介绍和实现 首先说它的性质&#xff1a;所有的节点都满足&#xff0c;左子树上所有的节点都比自己小&#xff0c;右边的都比自己大。 那这个结构有什么有用呢&#xff1f; 首先可以快速二分查找。还可以中序遍历得到升序序列&#xff0c;等等。。。 基本操…

python基础小白题

题目1&#xff1a;有1、2、3、4四个数&#xff0c;能组成多少个互不相同且无重复的三位数&#xff1f;都是多少&#xff1f; list_num[1,2,3,4] all_num[] for i in list_num: for j in list_num: for k in list_num : if (i!j) and (i!k) and (j!k): numi*100j*10k all_num…

python基础小白题2

题目11&#xff1a;判断101-200之间有多少个素数&#xff0c;并输出所有素数。 num[] for i in range(100,201): ji//2 for k in range(2,j): if i%k0: break else: num.append(i) print(一共有%d个素数\n这些素数是&#xff1a; %len(num),num ) 输出结果&am…