洛谷-基础-递推与二分笔记

洛谷-基础-递推与二分笔记

P1192 台阶问题

题目描述

有N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少11级),问到达第N级台阶有多少种不同方式。

输入格式

两个正整数N,K。

输出格式

一个正整数,为不同方式数,由于答案可能很大,你需要输出ans % 100003后的结果。

思路

​ 这个是典型的递推思路,类似于斐波拉契数列

#include<iostream>
using namespace std;
int n,m;
long long ans[100008];
int main(){
	cin>>n>>m;
	ans[0] = 1;
	for(int i = 1;i <= n;i++) {
		for(int j = 1;j <= m;j++){
			if(i - j < 0){
				break;
			}
			ans[i] = (ans[i] + ans[i - j])%100003;
		}
	}
	cout<<ans[n];
	return 0;
} 

P1025 数的划分

题目描述

将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

例如:n=7,k=3,下面三种分法被认为是相同的。

1,1,5;
1,5,1;
5,1,1.

问有多少种不同的分法。

输入格式

n( 所属区间(6,200] ),k( 所属区间[2,6])

输出格式

1个整数,即不同的分法。

思路

​ 使用组合数学思想,形成一个动态规划递推式

  1. 至少有一个盒子只有一个小球的情况数
  2. .没有一个盒子只有一个小球的情况数
#include<iostream>
using namespace std;
//动态规划 
//分俩种情况 
int n,k;
int f[205][8]; 
int main(){
	cin>>n>>k;
	for (int i=1;i<=n;i++) {
		f[i][1]=1;
		f[i][0]=1;
	}
	for (int i=2;i<=n;i++){
		for (int x=2;x<=k;x++){
			if (i>x) {
			 	f[i][x]=f[i-1][x-1]+f[i-x][x];
			}	  
            else {
            	f[i][x]=f[i-1][x-1];
            } 
		}
	}
    cout<<f[n][k];
	return 0;
} 

P1057 传球游戏

题目描述

上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。

游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没有传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m**次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。

输入格式

一 行 , 有 两 个 用 空 格 隔 开 的 整 数 n , m 。 ( 3 &lt; = n &lt; = 30 , 1 &lt; = m &lt; = 30 ) 一行,有两个用空格隔开的整数n,m。(3 &lt;= n &lt;= 30,1 &lt;= m &lt;= 30) n,m(3<=n<=30,1<=m<=30)

输出格式

1个整数,表示符合题意的方法数。

思路

​ 一开始,我使用简单的递归,发现超时大部分数据点

​ 然后使用动态规划 (更像当于是递推)

#include<iostream>
using namespace std;
int n,m;
int ans;
/* 50分基础递归 
void solve(int step,int now){
	if(now == 0){
		now = n;
	}
	if(now == n + 1){
		now = 1;
	}
	if(step == m){
		if(now == 1){
			ans++;
		}
		return;
	}
	else{
		solve(step + 1,now + 1);
		solve(step + 1,now - 1);
	}
}
int main(){
	cin>>n>>m;
	solve(0,1); 
	cout<<ans;
	return 0;
}
*/
int f[31][31];
int main(){
	cin>>n>>m;
	f[1][0] = 1;
	for(int k = 1;k <= m;k++) {
		f[1][k] = f[n][k - 1] + f[2][k - 1];
		for(int i = 2;i < n;i++) {
			f[i][k] = f[i - 1][k - 1] + f[i + 1][k - 1];
		}
		f[n][k] = f[1][k - 1] + f[n - 1][k - 1];
	}
	cout<<f[1][m];
	return 0;
}

P1216 数字三角形

题目描述

观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

         7 
      3   8 
    8   1   0 
  2   7   4   4 
4   5   2   6   5 

在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大

输入格式

第一个行包含 R(1<= R<=1000) ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

所有的被供应的整数是非负的且不大于100。

输出格式

单独的一行,包含那个可能得到的最大的和

思路

​ 动态规划,为了方便动态,采取从金字塔底部向上的做法

#include<iostream>
using namespace std;
int r;
int f[2000][2000];
int a[2000][2000];
int imax(int x,int y) {
	return x > y? x:y;
}
int main(){
	cin>>r;
	for(int i = 1;i <= r;i++){
		for(int j = 1;j <= i;j++){
			cin>>f[i][j];
			a[i][j] = f[i][j];
		}
	}
	for(int i = r - 1;i >= 1;i--) {
		for(int j = 1;j <= r ;j++) {
			f[i][j] = imax(f[i + 1][j],f[i + 1][j + 1]) + a[i][j];
		}
	}
	cout<<f[1][1];
	return 0;
}

P1182 数列分段 Section II

题面信息

在这里插入图片描述

思路

最大值最小化,最小值最大化 - 二分法+贪心

#include<iostream>
using namespace std;
int n,m;
int a[100008];
int imax(int x,int y) {
	return x > y ? x:y;
} 
int lef;
int rig;
int total = 0;
int tim = 0;
int ans = 0;
bool judge(int x,int a[]){
	total = 0;
	tim = 0;
    for(int i=0;i<n;i++){
        if(total+a[i]<=x){
        	total+=a[i];
        }
        else{
        	total=a[i];
			tim++;	
        } 
    }
    return tim>=m;
}
int main() {
	cin>>n>>m;
	for(int i = 0;i < n;i++) {
		cin>>a[i];
		lef = imax(lef,a[i]);
		rig+=a[i];
	}
	//cout<<"fuck";
	//return 0;
	while(lef<=rig){
		int mid = (lef + rig) / 2;
		if(judge(mid,a)){
            ans = mid;
			lef  = mid + 1;
		}
		else{
			rig = mid - 1;
		}
		
	}
	cout<<ans;
	
	return 0;
}

P1316 丢瓶盖

题目描述

陶陶是个贪玩的孩子,他在地上丢了A个瓶盖,为了简化问题,我们可以当作这A个瓶盖丢在一条直线上,现在他想从这些瓶盖里找出B个,使得距离最近的2个距离最大,他想知道,最大可以到多少呢?

输入格式

第一行,两个整数,A,B。(B<=A<=100000)

第二行,A个整数,分别为这A个瓶盖坐标。

输出格式

仅一个整数,为所求答案。

思路

最小值最大化问题 -> 二分法 + 贪心

其实,最主要的代码部分就是judge函数的编写

至于最后答案的输出,可以尝试一下,来对比获得.

#include<iostream>
#include<algorithm>
using namespace std;
int a,b;
int p[100008];
int ans;
bool judge(int limit){
	int total = 1;
	int here = 1;
	for(int i = 2;i <= a;i++){
		if(p[i] - p[here] >= limit){
			total++;
			here = i;
		}
	}
	if(total >= b){
		return true;
	}
	else{
		return false;
	}
} 
int main() {
	cin>>a>>b; 
	for(int i = 1;i <= a;i++) {
		cin>>p[i];
	}
	sort(p+1,p+a+1);
	int l = 1;
	int r = p[a] - p[l];
	while(l<=r){
		int mid = (l + r) / 2;
		if(judge(mid)){
			ans = mid;
			l = mid + 1;
		}
		else{
			
			r = mid - 1;
		}
	}
	cout<<ans;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值