问题 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. 写的太细了!Spring MVC拦截器的应用,建议收藏再看!

    Spring MVC拦截器 拦截器是Spring MVC中强大的控件,它可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作. 拦截器概述 对于任何优秀的MVC框架, ...

  2. Java-Netty前菜-NIO

    NIO NIO主要有三个核心部分组成: buffer缓冲区 Channel管道 Selector选择器 在NIO中并不是以流的方式来处理数据的,而是以buffer缓冲区和Channel管道配合使用来处 ...

  3. Java基础教程——方法引用

    方法引用 Lambda表达式的代码,是否可以再简洁?--方法引用 对象/类名::方法名 参数都不用写明. import java.util.function.Consumer; public clas ...

  4. java数组作为函数返回值

    1 //将一个二维数组行和列元素互换.存到另一个二维数组 2 package test; 3 4 public class test1_8 { 5 public static int[][] huhu ...

  5. 通过weakHashMap避免过期引用导致的内存泄漏

    问题由来 数组为基础实现的集合在退出元素时,并不会将引用指向空指针,过期引用存在对象便不会被回收. 措施 1.WeakHashMap当其中的key没有再被外部引用时,就会被回收.ThreadLocal ...

  6. 通过自定义拦截器优雅的导出Excel并标红的重复数据

    平时我们导入导出Excel的时候如果用poi导出,会发现光设置格式都要很多代码,看起来非常的不优雅.后来业务中遇到了需要导入非常巨大的Excel的需求.如果继续用poi的方式,因为poi把所有exce ...

  7. synchronized的底层原理?

    最近更新的XX必备系列适合直接背答案,不深究,不喜勿喷. 你能说简单说一下synchronize吗? 可别真简单一句话就说完了呀~ 参考回答: synchronize是java中的关键字,可以用来修饰 ...

  8. 技巧收藏|10个JavaScript常用数组操作方法

    摘要:这篇文章,向大家展示了在日常开发中,数组有哪些小技巧值得借鉴和学习. 在web前端开发第二阶段Javascript中,数组是一个重要且常见的知识点,我们经常将数据存储在数组中,遍历数组或替换数组 ...

  9. charles 常用功能 (六)抓包结果列表指展示关注的接口(focus on 功能)

    添加关注的接口 2.启用关注接口,添加过滤的地址 3.重新抓包结果 不在上一步配置中的接口,都会隐藏在other host中

  10. PyQt学习随笔:QTableWidget项sizeHint的作用以及与QHeadView的sectionResizeMode、ResizeToContents的关系

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在学习QTableWidgetItem的sizeHint()方法时,Qt自带材料中介绍sizeHin ...