洛谷-基础-递推与二分笔记
文章目录
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个整数,即不同的分法。
思路
使用组合数学思想,形成一个动态规划递推式
- 至少有一个盒子只有一个小球的情况数
- .没有一个盒子只有一个小球的情况数
#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 < = n < = 30 , 1 < = m < = 30 ) 一行,有两个用空格隔开的整数n,m。(3 <= n <= 30,1 <= m <= 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;
}