递推递归刷题:
问题 B: 【递推】偶数3的个数
时间限制: 1 Sec 内存限制: 64 MB
题目描述
“报告,我军已探出地雷阵中所有的地雷位置,并且还发现了一份使用说明书。”一个黑暗军团的小兵匆忙跑来,交给修罗王一张纸。
只见这张纸上面写道:“我是一颗萌萌的地雷,拆除我很容易,看到我身上标着的整数N了吗?你只要输入这个N位数中有多少个数中有偶数个数字3就可以把我拆除哦,加油!你行的。”
输入
一个整数N。
输出
输出这个N位数中有多少个数中有偶数个数字3。
样例输入
2
样例输出
73
#include <iostream>
using namespace std;
typedef long long ll;
const int N=3e5+5;
int a[N];//偶数个3的数量
int b[N];//奇数个3的数量
//思路
//对每一位数字而言,有两种选择:3或非3,非3的选择有9种方案(特别地,最高位只有8种)
//因此使用数组存储i位数时 奇数个3与偶数个3的数量,转移一下即可
//转移方法:偶数=偶数并且新一位不是3+奇数并且新一位是3
//奇数=奇数并且新一位不是3+偶数并且新一位是3
int main()
{
int n;
cin>>n;
if(n==1){//只有1位时,012456789,共9个数可只含0(偶数)个3
cout<<"9";
return 0;
}else{
a[1]=8;//最高位非0;为12456789均为非3,共8种。偶数
b[1]=1;//最高位为3时。奇数
for(int i=2;i<=n;i++){
a[i]=a[i-1]*9+b[i-1]*1;//偶数=之前高位的为偶数且这一位不是3或者之前高位的为奇数且这一位是3
b[i]=a[i-1]*1+b[i-1]*9;//奇数=之前高位的为奇数且这一位不是3或之前高位的为偶数且这一位为3
}
cout<<a[n];
}
return 0;
}
问题 C: 【递推】布阵
时间限制: 1 Sec 内存限制: 64 MB
题目描述
黑暗军团在城外的草地上布阵,如果把草地划分成很多大小一样的方格,看成无限大的棋盘,军团从中心点出发,每次只能向上或向左或向右移动一步(移动的过程中,走过的格子不能再次进入)。就能到达相邻的一个格子里,如果一共移动了N步,总共有多少种走法呢?
输入
一个整数即N,N≤30。
输出
输出步数。
样例输入
2
样例输出
7
#include <iostream>
using namespace std;
typedef long long ll;
const int N=3e2+5;
ll a[N],b[N];//数组a存储平移,数组b存储上移。
//思路:
//移动共有上,左,右三种,我将其划分为上移(向上)和平移(左/右)两大类。
//由于我们不能移动回已经走过的位置,平移操作方向一旦确定,便只可能向一个方向移动。也就是说,进行过平移操作的状态的下一步如果选择平移操作,方向是唯一确定的,而当上一步操作进行的是上移操作的时候,平移可以从左右两个方向当中选择一个。
//而上移操作不受上述条件限制,任何一个状态皆可进行上移操作。
int main()
{
int n;
cin>>n;
//初始状态:2种平移,1种上移。
a[1]=2;
b[1]=1;
for(int i=2;i<=n;i++){
a[i]=a[i-1]+b[i-1]*2;//上一步为平移则这一步平移只有一种;上一步为上移则这步有两个平移方向
b[i]=a[i-1]+b[i-1];//不管上一步是平移还是上移这一步都可上移
}
cout<<a[n]+b[n];
return 0;
}
问题 D: 【递推】极值问题
时间限制: 1 Sec 内存限制: 64 MB
题目描述
修罗王:“等了这么久,怎么攻城的魔法炮还没有响?”
邪狼满头大汗:“这魔法炮使用起来太复杂了,每次操作都需要输入验证码,首先它会产生一个正整数k,你要根据这个数输入正确的m和n两个整数才能发射。”
修罗王:“这是谁设计的炮啊,不考虑客户体验,界面友好性吗?让我来看看…”
现已知m,n为整数,且满足下列两个条件:
(1)m、n属于{1,2,…,k},即1≤m,n≤k
(2)(n2-mn-m2)2=1
你的任务是:根据输入的正整数k(1≤k≤109),求一组满足上述两个条件的m、n,并且使m2+n2的值最大。例如从键盘输入k=1995,则输出m=987 ,n=1597。
样例输入
1995
样例输出
987 1597
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define inf 1000000007
typedef long long ll;
using namespace std;
int main()
{
int k,m=1,n=1;
scanf("%d",&k);
int fb=m+n;
while(fb<=k)
{
m=n;
n=fb;
fb=m+n;
}
printf("%d %d",m,n);
return 0;
}
问题 E: 【递推】区域划分问题
时间限制: 1 Sec 内存限制: 64 MB
题目描述
已知黑暗军团的魔法炮发射轨迹成直线,现有n座魔法炮产生n(n≤500)条直线将地面(可视为平面,因为魔法炮具有降维属性,即可将三维空间降为二维空间)分割成了许多区域,并且已有p(p≥2)条直线相交于同一点,问n条直线最多能将平面分割成多少个不同的区域?
输入
输入一个数n和p。
输出
输出分割的区域数。
样例输入
3 2
样例输出
7
#include <iostream>
using namespace std;
int main()
{
int n,p;
cin>>n>>p;
int ans=2*p;
for(int j=p+1;j<=n;j++){
ans+=j;
}
cout<<ans;
return 0;
}
问题 F: 【递推】军事情报
时间限制: 1 Sec 内存限制: 64 MB
题目描述
俗话说,“不怕神一样的对手,就怕猪一样的队友。”虽然后世的历史学家们总是对修罗王的黑暗军团最终以惨败告终的原因争吵不休,但有一个原因是大家公认的,那就是邪狼把N封军事情报装在N个信封时,他居然全部都装错了信封。不管你信不信,反正我是信了,现求所有情报都装错信封共有多少种可能?
输入
一个整数N,1<N<20。
输出
一个整数,即可能数。
样例输入
2
样例输出
1
初始条件:S0=0,S1=0,S2=1(1放到2,2放到1) 思考:n个信封,跟前面的n-1个信封有什么关系呢? 首先,第n个情报不能放在第n个信封,第n个信封只能放1到n-1个情报中的其中一个,即第n个情报和第k个情报交换位置后,还是全部放错。这个k,可以是1到n-1中的任何一个。 交换后,全部情报都放错: 要么原来前面n-1个情报全部都放错,这时n和前面n-1个任何一个情报交换位置都可以——n-1个情报都放错有S(n-1)种可能,每种可能都有n-1中交换方法,即S(n) = S(n-1) * (n-1)。 要么原来前面n-1个情报有n-2个都放错(只有一个放对),这是只能和放对的那个情报交换位置——n-2个情报都放错有S(n-2)种可能,每种可能只有一种交换方法,但放对的情报可以是1到n-1,因此S(n) = S(n-2) * (n-1)。 两种情况合并起来,即Sn = (S(n-1) + S(n-2)) * (n-1)
#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
int n,i;
ll s[25]={0,0,1};
cin>>n;
for(i=3;i<=n;i++){
s[i]=(s[i-1]+s[i-2])*(i-1);
}
cout <<s[n];
return 0;
}