问题 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. 企业级工作流解决方案(九)--微服务Tcp消息传输模型之客户端处理

    客户端启动 客户端启动主要做三件事情,1. 从配置文件读取服务调用配置,存储到全局对象中.2. 指定客户端编解码器工厂.3. 预连接,即预先建立与服务端的通信Chanel. [DependsOn(ty ...

  2. How to realize one's ambition

    Work Overtime Can it work? To some extent, it parhaps works very well. What if you do little job and ...

  3. 了解 MySQL的数据行、行溢出机制吗?

    目录 一.行 有哪些格式? 二.紧凑的行格式长啥样? 三.MySQL单行能存多大体量的数据? 四.Compact格式是如何做到紧凑的? 五.什么是行溢出? 六.行 如何溢出? 七.思考一个问题 关注送 ...

  4. 使用FL Studio来制作停顿的效果

    停顿效果是一种在音乐创作中非常常用的音效,它能起到缓冲的作用,而且能使这段旋律更具节奏感,在比较激情的歌曲中尤为常见.例如知名歌手王力宏演唱的<火力全开>中就使用了停顿效果,为歌曲加了不少 ...

  5. C语言模拟实现先来先服务(FCFS)和短作业优先(SJF)调度算法

    说明 该并非实现真正的处理机调度,只是通过算法模拟这两种调度算法的过程. 运行过程如下: 输入进程个数 输入各个进程的到达事件 输入各个进程的要求服务事件 选择一种调度算法 程序给出调度结果:各进程的 ...

  6. zabbix地图显示全国延迟

    Zabbix 地图显示全国延迟 1.  效果图 2.  实现方法 将地图.png上传到zabbix为背景,上传红绿点.png为图标.然后新建主机关联模板为ICMP Ping,新建一个拓扑图调用地图为背 ...

  7. open()和with open() as的区别

    2020-03-18  20:37:55 open()和with open() as的区别 1 file = open("test.txt","r") 2 fo ...

  8. go创建动态库

    *nix *nix创建so比较方便,写好go代码之后,直接一条命令搞定. go build -buildmode=c-shared -o libgobblob.so 命令执行之后,会生成libgobb ...

  9. leetcode 练习--反转链表

    最近开始学习数据结构和算法的学习,也自然开始在 leetcode 上练习,所以每周大概会分享做过的leetcode 练习,尽量做到每天更新一道题目. 作为 leetcode 练习笔记的第一道题目,选择 ...

  10. MySQL二进制文件(binlog)

    二进制文件(binlog)记录对MySQL数据库执行更改的所有操作,但不包括SELECT和SHOW这类操作,因为这类操作没有改变数据. 为什么会有binlog? 首先 binlog 是 Server ...