问题 A: 2017夏令营第一阶段(Day3)问题A拆分数字I

题目描述

    把数字N拆分一些正整数的和,问有多少种不同的方法?
  例如:N=4,有1+1+1+1、1+1+2、1+2+1、1+3、2+1+1、2+2、3+1、4八种方法。

输入

  第一行:一个整数N,范围在[1,50]。

输出

  输出方案数。

样例输入

3

样例输出

4

 

第一题是一道典型的找子问题的题目,设f[i]表示N=i情况下的方案数,我们拿题目中N=4的情况讲述。
我们可以把他得到的答案(1+1+1+1、1+1+2、1+2+1、1+3、2+1+1、2+2、3+1、4)这堆东西分一下类别。
以1开头的有:1+1+1+1,1+1+2,1+2+1,1+3
以2开头的有:2+1+1,2+2,
以3开头的有:3+1
以4开头的有:4
我们不难发现,(以1开头为例),实际上就是f[3],因为开头1后面的数字的总和恰好为3,所以方案数自然为f[3]
以此类推,以2开头的方案数为f[2],以3开头的方案数为f[1],以4开头的为......
所以f[4]=f[3]+f[2]+f[1],那么f[3]=f[2]+f[1],我们发现,其实f[4]=2*f[3],所以以此类推f[3]=2*f[2]
我们以此找到规律f[n]=f[n-1]*2,(妙啊~
f[0]要初始化为1,qwq
来,上代码
1 #include<bits/stdc++.h>
2 using namespace std;
3 long long n,ans;        //看着数据大小,无奈地打起了long long(qwq
4 int main(){
5 scanf("%lld",&n);
6 ans=pow(2,n-1);      //运用f[n]=f[n-1]*2的规律
7 printf("%lld",ans);
8 return 0;
9 }

 完美!

问题 B: 2017夏令营第一阶段(Day3)问题B方格最短路径

题目描述

    有一个N*M的方格,每个格子里有一个数字,你从左上角格子开始,每次可以向下或向右走到相邻的格子里,一直走到右下角,问怎样走线路的格子中的数字和最小,输出这个最小值?

输入

  第一行:2个整数n,m,范围在[1, 100]。
  下面n行,每行m个整数,每个数范围在[1, 100] 。

输出

  路径上数字最小和。

样例输入

3 4
3 2 3 7
2 1 5 1
3 2 1 6

样例输出

15

这一道题也是一道经典子问题的题目。

这道题要求的值是从左上角到达右下角点(每到达一个点加上那个点的值)的值最小值。

设这道题的f[i][j]表示到点(i,j)时得到的最优值,那么我们最终要求的目标就是f[n][m]。

题目中要求只能走右边和下边,所以点f[n][m]只能从f[n-1][m]和f[n][m-1]两个点过来因此此时我们需要求出f[n-1][m]和f[n][m-1]两个点的最优值,以此内推,我们首先要求的是f[1][1]的最优值,然后往别的点便利最优值,从而得出状态转移方程,f[i][j]=min(f[i-1][j],f[i][j-1])+a[i][j]

妙啊~

上代码!

 1 #include<bits/stdc++.h>
2 using namespace std;
3 int n,m;
4 int a[1005][1005];
5 int f[1005][1005];
6 const int oo=0x7f7f7f;                       //最大值
7 int main(){
8 scanf("%d%d",&n,&m);
9 for(int i=1;i<=n;i++)
10 for(int j=1;j<=m;j++)
11 scanf("%d",&a[i][j]);
12 for(int i=0;i<=n+1;i++)
13 for(int j=0;j<=m+1;j++)
14 f[i][j]=oo;                      //这里需要初始化一下
15 f[0][1]=f[1][0]=0;
16 for(int i=1;i<=n;i++)
17 for(int j=1;j<=m;j++){
18 f[i][j]=min(f[i][j-1],f[i-1][j])+a[i][j];
19 }
20 printf("%d",f[n][m]);
21 return 0;
22 }

完美!

问题 C: 2017夏令营第一阶段(Day3)问题C最长上升序列

题目描述

    有N个数,要求从前到后挑选一些数,要求这些数是上升的(一个比一个大)。问最多能选多少个数?

输入

  第一行:1个整数N,范围在[1, 10000]。
  第二行有N个整数,每个数范围在[1, 1000000] 。

输出

  最多挑选的个数。

样例输入

8
9 1 3 7 4 1 5 5

样例输出

4

如果去过洛古的大佬,应该知道有一道题叫做导弹拦截,那道题跟这道题及其相似。

这道题设f[i]为当找到第i个数字时的最优值。

那么我们可以枚举前面i前面的数值然后如果找到是满足递增情况的时候就可以加多一种情况,因此方程就是if(a[j]>a[i])f[i]=max(f[i],f[j]+1);

上代码!

 1 #include<bits/stdc++.h>
2 using namespace std;
3 int n,f[10005];
4 int a[10005];
5 const int oo=0x7f7f7f;
6 int mmax;
7 int main(){
8 scanf("%d",&n);
9 a[0]=-oo;
10 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
11 for(int i=n;i>=1;i--){
12 f[i]=1;
13 for(int j=i+1;j<=n;j++)
14 if(a[j]>a[i])f[i]=max(f[i],f[j]+1);
15 mmax=max(f[i],mmax);                  //统计最优值
16 }
17 printf("%d",mmax);
18 return 0;
19 }
 完美!

问题 D: 2017夏令营第一阶段(Day3)问题D拆分数字II

题目描述

  把数字N拆分一些正整数的和,问有多少种本质不同的方法?
  例如:N=4,有1+1+1+1、1+1+2、1+3、2+2、4五种方法。
  提示:1+3和3+1是本质相同的方法。

输入

  第一行:一个整数N,范围在[1,50]。

输出

  输出方案数。

样例输入

3

样例输出


3


从题面分析本题与第一题类似但又不同,因为以数学的思想讲第一题是排列,而本题为组合。
我们不妨把他想象成完全背包。
以题目中的例子“N=4,有1+1+1+1、1+1+2、1+3、2+2、4”,我把得到组合的第一个数字称为num[i][1](num[1][1]=1,num[1][2]=1,num[1][3]=1,num[1][4]=1……num[4][1]=4)
那么num[i][j]可以放1~N的数字,然后按照完全背包的过程就是每个数字(1~N)你可以取无限次,只要满足num[i][1]+num[i][u]总和为N就行了。
所以我们可以用完全背包的思路解决这道题。

上代码~!

 1 #include<bits/stdc++.h>
2 using namespace std;
3 long long n,f[10005];
4 int main(){
5 scanf("%lld",&n);
6 f[0]=1;                    //千万别少了初始化
7 for(long long i=1;i<=n;i++)        //完全背包
8 for(long long j=i;j<=n;j++)
9 f[j]+=f[j-i];            
10 printf("%lld",f[n]);
11 return 0;
12 }

完美!

问题 E: 2017夏令营第一阶段(Day3)问题E :砖块(brick)

题目描述

  现有一种形状为1*2的砖块,要用这种砖块摆成宽为2,长为n的墙,问有多少种方案?

输入

  该题有若干组测试数据,每组数据一行,一行一个正整数n(n<=1000000)表示长,当n=0时结束。

输出

  对应每组的方案数(模1000000007)。

样例输入

1
2
3
0

样例输出

1
2
3

提示

【样例解释】:

这道题跟一道叫做“台阶问题”的题目很相似。(也就是说你可以双倍经验

我们不妨把1*2的方块竖着放定义为走1步,而横着放定义为走2步。

那么问题就被我们转换成一个新问题:一个n阶的台阶,你可以走1步或者走2步,最后一步必须走到终点,问有多少种走法。

(然而台阶问题可以走1~K步,也就是说这道题比台阶问题还简单。

我们设f[i]为走到第i个位置的时候的方案总数,那么我们想要求的答案就是f[n]。

那么我们怎么得到f[n]呢?显然可以走1步或者2步,我们就可以从f[n-1]和f[n-2]两个格子过来。

又因为加法原理,我们得到公式:f[n]=f[n-1]+f[n-2],以此类推,f[i]=f[i-1]+f[i-2]。

这不就是著名的肥波纳妾数列吗,呸(斐波那契数列【手动滑稽】

好了不多说,上代码!

 1 #include<bits/stdc++.h>
2 using namespace std;
3 long long n=1,k,a[1000005];
4 const long long mod=1000000007;          //别忘了mod
5 int main(){
6 while(n!=0){
7 memset(a,0,sizeof(a));
8 scanf("%lld",&n);
9 if(n==0)return 0;
10 a[0]=1;
11 for(long long i=1;i<=n;i++)
12 a[i]=a[i-1]+a[i-2],a[i]%=mod;    //肥波纳妾啦(
13 printf("%lld\n",a[n]);
14 }
15 return 0;
16 }

完美~!

问题 F: 2017夏令营第一阶段(Day3)问题F :合唱队形

题目描述

  N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
  合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1 < …Ti+1 > … > TK(1 <= i <= K)。
  你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入

  第一行是一个整数N(2 <= N <= 200),表示同学的总数。
  第二行有n个整数,用空格分隔,第i个整数Ti(130 <= Ti <= 230)是第i位同学的身高(厘米)。

输出

  包括一行,这一行只包含一个整数,就是最少需要几位同学出列。

样例输入

8
186 186 150 200 160 130 197 220

样例输出

4

  

其实这道题我什么也不想说,其实就是第三题的升级版,你只需要两边都dp一遍就好了,上代码~!(没看懂得朋友可以去琢磨第三题

 1 #include<bits/stdc++.h>
2 using namespace std;
3 int n,a[10005],ans,zans[10005],zans1[10005];
4 int main(){
5 scanf("%d",&n);
6 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
7 for(int i=1;i<=n;i++)
8 for(int j=1;j<=i;j++)
9 if(a[i]>a[j])zans[i]=max(zans[i],zans[j]+1);      //像第三题一样dp一遍左边(从左往右
10 for(int i=n;i>=1;i--)
11 for(int j=n;j>=i;j--)
12 if(a[i]>a[j])zans1[i]=max(zans1[i],zans1[j]+1);    //像第三题一样dp一遍右边(从右往左
13 for(int i=1;i<=n;i++)
14 ans=max(ans,zans[i]+zans1[i]+1);               //相加便利得结果
15 printf("%d\n",n-ans);                        //剩下的就是需要移除的人的个数
16 return 0;
17 }

问题 G: 2017夏令营第一阶段(Day3)问题G :维修栅栏(fence)

题目描述

  农场的栅栏年久失修,出现了多处破损,晶晶准备维修它,栅栏是由n块木板组成的,每块木板可能已经损坏也可能没有损坏。晶晶知道,维修连续m个木板(这m个木板不一定都是损坏的)的费用是sqrt(m)。可是,怎样设计方案才能使总费用最低呢?请你也来帮帮忙

输入

  第一行包含一个整数n(n≤2500),表示栅栏的长度;
  第二行包含n个由空格分开的整数。如果第i个数字是0,则表示第i块木板已经损坏,否则表示没有损坏。

输出

  仅包含一个实数,表示最小维修费用;注意:答案是小数,最少精确到0.001。

样例输入

9
0 –1 0 1 2 3 0 –2 0

样例输出

3.000

  

这一道题非常经典,相对于前几道题有点难度,嗯。

首先来理解一下题目,有些朋友会想欸,我一个个修他不香吗,为什么那么麻烦。

如果你这样理解你就错了,我们手动水一组样例:“0,1,0”

那么如果我们一个个修我们就要花费√(1)+√(1)=2的费用

但是你有没有想过√(3)=1.732050807568877……,而且<√(1)+√(1)

所以这就是我们要研究的问题。

我们设f[i]为修到第i个围栏时得到的最小费用。

那么我们要求得自然就是f[n]。

那么f[n]怎么求呢?

我们假设第i个是数字“0”。

那么f[i]现在面临得问题就是单个修还是连着修,那么我们不妨把这些结果一一算出来比较大小。

我们用一个j去枚举连续修j个栅栏时候得情况那么我们如果连续修得话,结果自然就是f[i-j]+sqrt(j),所以我们只需要比较这些f[i-j]+sqrt(j)找到最小得一个,他就是f[i]得值。

从而得到方程:f[i]=min(f[i],f[i-j]+sqrt(j));

上代码!

 1 #include<bits/stdc++.h>
2 using namespace std;
3 int n;
4 double f[10005];
5 int wall[100005];
6 const int oo=0x7f7f7f;
7 int main(){
8 scanf("%d",&n);
9 for(int i=1;i<=n;i++)scanf("%d",&wall[i]);
10 for(int i=1;i<=n;i++){
11 if(!wall[i]){                  //判断如果到达一个需要修得点得时候就判断怎么修这个点
12 f[i]=oo;
13 for(int j=1;j<=i;j++){          //枚举修j个栅栏得情况
14 f[i]=min(f[i],f[i-j]+sqrt(j));   //状态转移方程
15 }
16 }
17 else f[i]=f[i-1];                //如果不需要修那么就继承上一代得意志(此时得到的最优值就是上一个的值
18 }
19 printf("%.3f",f[n]);                //别忘了3位小数
20 return 0;
21 }

DP-DAY3游记的更多相关文章

  1. 清北学堂dp图论营游记day3

    .状态压缩dp: 对于这个我们引入二进制状态压缩,因为任何一个数都可以二进制表示,而其二进制表示上每一位都可以表示当前位置是否有元素,这就构成了状态压缩. 对于这个题,上下行&一下就行. 状压 ...

  2. CCPC-Wannafly Winter Camp Day3 Div1 - 精简改良 - [生成树][状压DP]

    题目链接:https://zhixincode.com/contest/14/problem/D?problem_id=206 样例输入 1  5 5 1 2 1 1 3 1 2 4 1 2 5 1 ...

  3. 【CCPC-Wannafly Winter Camp Day3 (Div1) D】精简改良(状压DP)

    点此看题面 大致题意: 给你一张图,定义\(dis(i,j)\)为\(i\)与\(j\)的最短距离,现要求删去若干条边,使得图仍然联通,且\(\sum_{i=1}^n\sum_{j=i+1}^ndis ...

  4. 帝都Day3——各种dp

    备注:Day1 Day2记得笔记太233,所以就不发了 备注2:Day4~Day7发不发看心情qaq (7.17持续更新中...) 动态规划A 记忆化搜索 & 动态规划初步 8点15: 杨姓d ...

  5. 牛客国庆集训派对Day3 B Tree(树形dp + 组合计数)

    传送门:https://www.nowcoder.com/acm/contest/203/B 思路及参考:https://blog.csdn.net/u013534123/article/detail ...

  6. 清北学堂dp图论营游记day2

    上午讲数位dp和背包问题. 先讲背包: 完全背包:换了个顺序: 多重背包: 多重背包优化: 这样把每个物品分成这些组,那么把他们转变成不同的物品,就变成了01背包问题: 滑动窗口取最值问题.单调队列优 ...

  7. 清北学堂dp图论营游记day1

    讲课人: 老师对dp的理解是类似于分治思想,由小状态推出大状态.不同的是分治算法没有重叠子问题. dp把子问题越划越小,从而推出了基础状态.然后是dp方程,要满足简洁性,并且充分描述能够影响最后结果的 ...

  8. 清北学堂dp图论营游记day6

    xysq主讲: 求点双和边双代码: 对所有点进行染色,如果存在一种方案使得相邻的点不同色,那么他就是个二分图. 二分图两种求法,1,dfs求增广路. 2,网络流:最大流=最小割 差分约束: 下午又要考 ...

  9. 清北学堂dp图论营游记day5

    ysq主讲: tarjan缩点+拓扑+dij最短路. floyd..... 单源..最长路... 建正反两个图. 二分答案,把大于答案的边加入到新图中,如果能走过去到终点,就可以. 或者:从大到小加边 ...

  10. 清北学堂dp图论营游记day4

    依然zhx讲. 讲了概率与期望: 期望:事件结果的平均大小.记作E(x). E(x)=每种结果的大小与其概率的乘积的和. 例如,记掷一枚骰子的点数为x E(x)=1*(1/6)+2*(1/6)+3*( ...

随机推荐

  1. 学好Flex布局并不容易

    1. Flex布局介绍 CSS的传统布局解决方案,基于盒状模型,依赖display属性.position属性.float属性,对于一些特殊的布局,例如垂直居中,往往要想很多hack的方法来解决. 20 ...

  2. [大雾雾雾雾] 告别该死的 EFCore Fluent API (续)

    朋友们好啊, 我是 .NET 打工人 玩双截棍的熊猫 刚才有个朋友问我 猫猫发生什么事了 我说 怎么回事? 给我发了一张截图 我一看!嗷!原来是zuo天有两个数据库, 一个四十多岁,一个三十多岁 它们 ...

  3. Guitar Pro小课堂之如何演奏刮弦

    每当我们听到吉他现场演出的时候,看到吉他手在激烈的刮弦时,都觉得很酷,非常有感染力.刮弦在我们弹吉他或编曲时,会经常用到,虽然时间很短,但会为你加分不少. 那么我们应该如何演奏刮弦呢,我们先用E5和弦 ...

  4. 【干货】linux使用nginx一个80端口部署多个项目(spring boot、vue、nuxt、微信小程序)

    本人只有一个阿里云的ip和一个已经解析过的域名,然后想用80端口部署多个项目,比如输入: www.a.com和www.b.com与www.c.com就能访问不同项目,而不用输入不同端口号区分. 1.这 ...

  5. 蚂蚁上市员工人均一套大 House,阿里程序员身价和这匹配吗?

    作者 | 硬核云顶宫 责编 | 伍杏玲 出品 | CSDN(ID:CSDNnews) 上周,蚂蚁集团迎来IPO,其发行价格将达到68.8元,总市值将突破2万亿元.市场对蚂蚁的成长性有着充分的信心,为了 ...

  6. 基于混沌Logistic加密算法的图片加密与还原

    摘要 一种基于混沌Logistic加密算法的图片加密与还原的方法,并利用Lena图和Baboon图来验证这种加密算法的加密效果.为了能够体现该算法在图片信息加密的效果,本文还采用了普通行列置乱加密算法 ...

  7. JDK8HashMap的一些思考

    JDK8HashMap 文中提及HashMap7的参见博客https://www.cnblogs.com/danzZ/p/14075147.html 红黑树.TreeMap分析详见https://ww ...

  8. 基于 MongoDB 动态字段设计的探索

    一.业务需求 假设某学校课程系统,不同专业课程不同 (可以动态增删),但是需要根据专业不同显示该专业学生的各科课程的成绩,如下: 专业 姓名 高等数学 数据结构 计算机 张三 90 85 计算机 李四 ...

  9. 极简Linux下安装极简桌面

    sudo apt install -y xorg lxde-core vnc4server 设置密码:vncpasswd 然后先开启服务,然后再终止服务:(这是为了创建一个默认的配置文件)vncser ...

  10. 第7.7节 案例详解:Python类继承机制

    本节实现一个类继承的小程序,下面一边结合代码一边介绍相关继承的知识.例子以车.汽车为例,车为父类.汽车为子类. 一.    定义父类Vehicle class Vehicle():    def __ ...