To_Heart—题解——递推测试
1.舞蹈毯
题目描述
由于长期缺乏运动,小黑发现自己的身材臃肿了许多,于是他想健身,更准确地说是减肥。
小黑买来一块圆形的毯子,把它们分成三等分,分别标上A、B、C,称之为“跳舞毯”,他的运动方式是每次都从A开始跳,每次都可以任意跳到其他块,但最后必须跳回A,且不能原地跳.为达到减肥效果,小黑每天都会坚持跳N次,有天他突然想知道当他跳次时共几种跳法,结果想了好几天没想出来。
现在就请你帮帮他,算出总共有多少跳法。
-
输入格式 测试输入包含若干测试用例。每个测试用例占一行,表示N的值。当N为0时输入结束。
-
输出格式 每个测试用例的输出占一行,由于跳法非常多,输出其对10000取模的结果
样例输入
2
3
4
0
样例输出
2
2
6
数据范围与提示
1 <= n <= 1000
分析
首先,我们知道递推一般是最后一步来找公式,就如这道水的不能再水的经典题
先观察
设N次有a[n]种情况,我们发现,若第N次后要回到A,那么第N-2次就会有2种情况:
- 当N-2在A时,可从A到B再返回A或到C再返回A,则有2种情况,又因为这两种情况回A都需两步,即:共有 *a(n-2)2 种情况
- 当N-2再B或C时,跳回A都只有一种情况,即:有 a[n-1] 种情况。
代码如下AC不了别找我:
#include<cstdio>
int main(){
int n[1005]={},x;
n[2]=2;
n[3]=2;
for(int j=4;j<=1000;j++){
n[j]=(n[j-1]+n[j-2]*2)%10000;
}
while(scanf("%d",&x)!=EOF&&x){
printf("%d\n",n[x]);
}
return 0;
}
2. 集合的和
好难好难好难
太“水”了~~~~
题目描述
农夫约翰命令他的牛去寻找不同的集合,这些集合里面的数字加起来刚好等于农夫约翰给定的数字n,而且集合里面的数字只能是2的次方。例如,农夫约翰给定的数字为7,则这些不同的集合一共有6个,分别如下:
1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+2+2
1+1+1+4
1+2+2+2
1+2+4
请你帮助农夫约翰数出对于数字n来说,一共有多少个这样不同的集合?
-
输入格式 输入有多组测试数据,每组测试数据有一行,包含一个整数n,表示农夫约翰所给定的数字。
-
输出格式 对于每组测试数据输出只有一行,包含一个整数,表示对于数字n来说,不同的集合的个数。由于这个数字可能非常的大,对结果取模1e9
样例输入
7
10000
样例输出
6
573449444
数据范围与提示
1<=N<=1,000,000
分析
这道题十分毒简单:
首先,
把第N个集合个数看成a[n]
然后:
1.我们知道:除1外,所有奇数的集合都等于其前一个偶数的集合个数
2.把N看成N-1和1,则:
1.若N-1本身就可以凑成集合,那么+1就不会对其造成影响(因为1就是2的幂),就有a[n-1]种情况;
2.若N-1不能凑出集合,那么就会多出一个1来,和后面的1一加,就没有一了,此时的个数和N/2的个数一样(因为每个数字除以2并不影响总集合个数),就有a[n/2]种情况。
综上所述
亮代码!错了也不能怪我
#include <cstdio>
int a[10000005]; //定义全局,否则会爆
int main(){
int n;
a[1]=1;
for(int i=2;i<=10000000;i++) {
if(i%2==0)
a[i]=(a[i-1]+a[i/2])%1000000000;
else
a[i]=a[i-1]%1000000000; //也可以放后面一起模
}
while(scanf("%d",&n)!=EOF)
printf("%d\n",a[n]);
return 0;
}
3.帖瓷砖
题目描述
现有2×1大小的瓷砖若干个,现在要使用这些瓷砖来铺一条宽度为3,长为n的小路,请问一共有多少种贴法?
-
输入格式 输入有多组测试数据,每组测试数据包含一个整数n
-
输出格式 每组测试数据输出1个整数,表示当前长度的小路的贴法总数。
样例输入
2
8
12
样例输出
3
153
2131
数据范围与提示
1<=N<=30
分析
设:第N个贴法总数a[n]个。
-
奇数不可能
-
偶数:
1.a[n]=3a[n-2]+2a[n-4]+2a[n-6]+…+2a[2]+2*a[0];
2.a[n-2]=3a[n-4]+2a[n-6]+…+2a[2]+2a[0]
3.a[n]-a[n-2]=3*a[n-2]-a[n-4]
化简得:
4.a[n]=4*a[n-2]-a[n-2]
这就是通项公式!!!
代码如下依旧不敢保证AC
#include<cstdio>
int main(){
long long n[35]={};
int x;
n[2]=3;
n[4]=11; //2项和4项需要赋初值,因为公式对它们没用
for(int i=5;i<=30;i++){
if(i%2==0)
n[i]=4*n[i-2]-n[i-4];
}
while (scanf("%d",&x)!=EOF)
printf("%d\n",n[x]);
return 0;
}
4.分糖果
题目描述
马老师要把N颗糖果分给K个学生,并且要保证每个学生都能分到糖果,问一共有多少种不同的分配方案?例如:N=5,K=3,共有6种不同的方案。
5=1+2+2
5=1+3+1
5=2+1+2
5=2+2+1
5=3+1+1
-
输入格式 仅有一行,包含两个用空格隔开的自然数N和K。
-
输出格式 只有一行,包含一个整数,表示将N颗糖果分给K个学生的方案总数,具体方案不需要输出。
样例输入
5 3
样例输出
6
数据范围:
N<=200,K<=10
分析
-
将N颗糖果分给K个学生的方案总数表示为a[i][j],其中i=学生数,j=糖果数;
-
a[i][i]和a[1][j]的初值都为1(糖果数和人数相等,每人有且只有1颗;人数唯一,所有糖归他)
-
如下:
1.a[i][j]=a[i-1][j-1]+a[i-1][j-2]+…+a[i-1][i-1]
2.a[i][j-1]=a[i-1][j-2]+a[i-1][j-3]+…+a[i-1][i-1]
3.a[i][j]-a[i][j-1]=a[i-1][j-1]
化简得:
a[i][j]=a[i][j-1]+a[i-1][j-1]
通项公式又出来啦!!!
所以,是时候亮出最后的代码啦:
虽然完美撒花但我仍不保证代码的正确性
#include<cstdio>
long long n,k,a[15][205];
int main(){
scanf("%lld %lld",&n,&k);
for(int i=1;i<=10;i++){
a[i][i]=1;
}
for(int i=1;i<=200;i++){
a[1][i]=1;
}
for(int i=2;i<=10;i++){
for(int j=2;j<=200;j++){
a[i][j]=a[i][j-1]+a[i-1][j-1];
}
}
printf("%lld",a[k][n]);
return 0;
}