CCF-NOIP-2018 提高组(复赛)模拟试题 楼梯问题

探讨CCF-NOIP-2018竞赛中的楼梯问题,涉及递推公式和矩阵乘法优化求解不同上楼方案数量,适用于n步台阶和最多m级跳跃的组合问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CCF-NOIP-2018 提高组(复赛)模拟试题 楼梯问题

[Question Description]

​ 一层楼共有 n 级台阶,一次可以上至少 1 级但**不超过** m 级台阶,求有多少种不同的上楼方案数。由于结果可能很大,你只需要输出结果对 10,007 取模的值即可。

[Input Format]

输入数据只有一行,包含两个正整数 nm

[Output Format]

一个整数,表示所求结果对 10,007 取模的值。

[Sample Input 1]

4 3

[Sample Output 1]

7

[Sample Explanation 1]

共有 7 种不同的上楼梯方案,分别为:

  1. 第 1 步上 1 级,第 2 步上 1 级,第 3 步上 1 级,第 4 步上 1 级。
  2. 第 1 步上 1 级,第 2 步上 1 级,第 3 步上 2 级。
  3. 第 1 步上 1 级,第 2 步上 2 级,第 3 步上 1 级。
  4. 第 1 步上 2 级,第 2 步上 1 级,第 3 步上 1 级。
  5. 第 1 步上 2 级,第 2 步上 2 级。
  6. 第 1 步上 1 级,第 2 步上 3 级。
  7. 第 1 步上 3 级,第 2 步上 1 级。

[Sample Input 2]

1024 5

[Sample Output 2]

8590

[Data Scale And Agreement]

测试点编号n的规模m的规模
11 ≤ \leq n ≤ \leq 10m = 1
21 ≤ \leq n ≤ \leq 10m = 1
31 ≤ \leq n ≤ \leq 10m = 1
41 ≤ \leq n ≤ \leq 10m = 1
51 ≤ \leq n ≤ \leq 10m = 2
61 ≤ \leq n ≤ \leq 10m = 2
71 ≤ \leq n ≤ \leq 10m = 2
81 ≤ \leq n ≤ \leq 10m = 2
91 ≤ \leq n ≤ \leq 10m = 3
101 ≤ \leq n ≤ \leq 10m = 3
111 ≤ n ≤ 10,0002 ≤ m ≤ 10
121 ≤ n ≤ 10,0002 ≤ m ≤ 10
131 ≤ n ≤ 100,0002 ≤ m ≤ 10
141 ≤ n ≤ 100,0002 ≤ m ≤ 10
15n = 233,333,333m = 5
16n = 666,666,6662 ≤ m ≤ 5
17 1 1 1 ≤ n ≤ 1 0 9 10^9 109m=2
18 1 1 1 ≤ n ≤ 1 0 12 10^{12} 1012m=2
191 ≤ n ≤ 1 0 15 10^{15} 10152 ≤ m ≤ 10
201 ≤ n ≤ 1 0 18 10^{18} 10182 ≤ m ≤ 10

[Solution]

Emmm… 这道题被加强了又加强,开始是只能踏一或二步,后来可以踏一到m步,但数据没有这么变态,现在魔改数据真tm加强的炉火纯青

70~80分做法

可得递推式为 F n = F n − 1 + F n − 2 + . . . + F n − m F_n=F_{n-1}+F_{n-2}+...+F_{n-m} Fn=Fn1+Fn2+...+Fnm

双重循环递推,第十五和十六测试点打表

100分做法

真牛逼

递推是不行滴

矩阵乘法好处大,谁说对了谁用它

构造矩阵加速递推,式子同上:

#include<bits/stdc++.h>
using namespace std;
const int mod=10007;
int n,m;
struct matrix
{
	int mat[20][20];
	matrix operator *(const matrix &B)
	{
		matrix res;
		memset(res.mat,0,sizeof res.mat);
		for(int i=1;i<=m;i++)
			for(int j=1;j<=m;j++)
				for(int k=1;k<=m;k++) res.mat[i][j]=(res.mat[i][j]+mat[i][k]*B.mat[k][j])%mod;
		return res;
	} 
}tmp,ans;
matrix qpow(matrix a,int b)
{
	matrix rs;
	memset(rs.mat,0,sizeof rs.mat);
	for(int i=1;i<=m;i++)
		for(int j=1;j<=m;j++)	if(i==j) rs.mat[i][j]=1;
	while(b)
	{
		if(b&1) rs=rs*a;
		a=a*a;
		b>>=1;
	}
	return rs;
}
int main()
{
	
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		tmp.mat[i][m]=1;
	for(int i=2;i<=m;i++) tmp.mat[i][i-1]=1;
	
	ans.mat[1][0]=1;
	for(int i=1;i<=m;i++)
		for(int j=0;j<i;j++) ans.mat[1][i]=ans.mat[1][i]+ans.mat[1][j]%mod;		
	ans=ans*qpow(tmp,n-1);
	printf("%d",ans.mat[1][1]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值