【考试题解】 递归递推

T1:station

题目描述:
小 VHOS 带着 N 颗山楂球来到 A 班的阵地准备缩到位置上吃山楂球。
但是 A 班大佬们太强了,所以小 VHOS 每经过一个 A 班大佬身边, 他都需要交出他
手中一半的山楂(向下取整);
但是 A 班大佬看在小 VHOS 没吃午饭,都会从他们所拿的那一半中额外留出一颗山
楂球给小 VHOS。
经过重重的关口,小 VHOS 只剩下 X 颗山楂,他的午饭没了 qwq…小 VHOS 很菜,
他心情慌张,连自己还剩几颗山楂都不知道了 qwq…
所以帮小 VHOS 统计剩余山楂的任务就交给了你。
输入格式:
一行 2 个整数 N, M,表示原先带到 A 班的山楂总数, A 班同学的人数。
输出格式:
一行整数,表示小 VHOS 剩余的山楂球个数。
样例数据:
Sample Input Sample Output
8 1 5
数据规模与运行资源限制
对于 30%的数据, N≤10, M≤3;
对于 80%的数据, N≤1×105, M≤20;
对于 100%的数据, N≤1×107, M≤2×109;

如果你一看,这道题就是一个模拟,即80分,具体实现如下:
1.假设剩下的数量为n,则会取走n/2
2.那么会剩下n-n/2
3.因为A班的人很同情它要+1,所以剩下的是n=n-n/2+1
4.然后枚举1-i,n不断减少即可
假如你想拿100分,则必须要减少优化:
1.可以看出M>N,所以N除到一定大小的时候会在一个固定的数字徘徊
2.不难发现:2-2/2+1=2;3-3/2(c++运算下)+1=3时值保持固定不变,故加上特判对其优化即可.
具体代码如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    freopen("station.in","r",stdin);
    freopen("station.out","w",stdout);
    int n,m;
    cin>>n>>m;
    for (int i=1;i<=m;i++)
    {
        int take=n/2;
        n-=take;
        n++;
        if (n==2||n==3) break;
    }
    cout<<n;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2:stairs

题目描述
OpportunityFan(以下简称 OF)正在准备体育考试,他为跳远感到忧愁。 VHOS
建议他每天跳 N 级台阶,锻炼爆发力。为了增加虚伪之力, OF 给自己制定了一项规则:
当他跳到偶数级台阶时,他可以跳 2 级或 3 级;
当他跳到奇数级台阶时, 他可以跳 1 级或 4 级。
你需要求, 若刚开始时他处在 0 级(属于偶数), 他跳到 N 级的方法数量是多少。
输入格式
一行,一个整数,表示 N。
输出格式
一行,一个整数,表示答案。 最后的答案 mod 1×109+7。
样例数据
Sample Input Sample Output
9 4
数据规模与运行资源限制
对于 20%的数据N ≤ 10
对于 80%的数据N ≤ 1 × 106
对于 100%的数据N ≤ 5 × 107
时间限制: 1s
空间限制: 512MB

不难看出,这是一道非常简单的递推,设当前的点为i,则:
①当i是偶数的时候,i是由i-2和i-3级阶梯转移过来的,根据加法原理,可得递推式:f(i)=f(i-2)+f(i-3)(i%2==0).
②同理,当i是奇数时,可得到递推式:f(i)=f(i-1)+f(i-4)
为了方便枚举,我们可以选择从0开始累加:
故可以得到:
f[i+1]+=f[i+4]+=fi
f[i+2]+=f[i+3]+=fi
一个惊人的错误:
在全局变量内声明特别大的数组不能用={},否则会造成编译超时,就像我本来用了f[60000000]={1},就错了
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int M=1000000000+7;
int f[60000000];
int main()
{
    freopen("stairs.in","r",stdin);
    freopen("stairs.out","w",stdout);
    int n;
    f[0]=1;
    cin>>n;
    for (int i=0;i<=n;i++)
    {
        if (i%2==0) 
        {
            f[i+2]=(f[i+2]+f[i])%M;
            f[i+3]=(f[i+3]+f[i])%M;
        }
        if (i%2==1)
        {
            f[i+1]=(f[i+1]+f[i])%M;
            f[i+4]=(f[i+4]+f[i])%M;
        }
    }
    cout<<f[n]%M;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T3:cat

题目描述:
VHOS 养了一只从外星来的猫, 这只猫的基因由三种字符组成: c, a, t。
但这只猫会疯狂进化,每过一个单位时间, 这只猫的基因都会复制一遍,并在原基因
和复制出来的基因中加入 t-1 个 a ,组成新基因。
当 t=1 时,它的基因为”cat” ;
当 t=2 时, 它的基因为“catacat” ;
当 t=3 时, 它的基因为“catacataacatacat” 。
VHOS 想知道在这只猫的第 i 位的基因为什么,什么时候出现了这位基因。
输入格式:
第一行一个数 t,表示问题个数;
第 2 到 t+1 行,每行一个整数 i。
输出格式:
t 行每行第一个为字符,表示这只猫的第 i 位的基因;
第二个为一个整数,表示出现这位基因的时间。
input
3 7
13
17
output
t 2
a 3
a 4

可以看出,这是一道递归题
这里就不做过多的解释:见小顾的字符游戏一题
参考代码:

#include<bits/stdc++.h>
using namespace std;
int F[30]={};
string Ans[3]={"c ","a ","t "};
void dfs(int X)
{
    if (X==1||X==2||X==3){cout<<Ans[X-1];return;}
    if (X<1) return;
    int temp;
    for (temp=1;temp<=29;temp++)
        if (X>=F[temp-1]+1&&X<=F[temp])
            break;
    if (F[temp-1]+1<=X&&F[temp-1]+temp-1>=X){cout<<Ans[1];return;}
    dfs(X-temp-F[temp-1]+1);
    return;
}
void Find(int X)
{
    for (int Find_ans=1;Find_ans<=29;Find_ans++)
        if (X>=F[Find_ans-1]+1&&X<=F[Find_ans])
        {
            cout<<Find_ans<<endl;
            return;
        }
    return;
}
int main()
{
    freopen("cat.in","r",stdin);
    freopen("cat.out","w",stdout);
    F[1]=3;
    for (int i=2;i<=29;i++)
        F[i]=F[i-1]*2+i-1;
    int T;
    cin>>T;
    while (T--)
    {
        int K;
        cin>>K;
        dfs(K);
        Find(K);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T4:monkey

题目描述
朝三暮四是一个大家耳熟能详的故事, 当 VHOS 从虚伪大魔王的城堡逃出来时,顺了
m 只相同的猴子出来(是不是很神奇?)。
可现在有一个问题: 猴子们饿了。
VHOS 有 n 个相同的栗子,他在给猴子分栗子时,一定要满足每个猴子都有栗子,他
一共有多少种分栗子的方法(对 1×109+7 取模)。
输入格式
一行两个数 n, m。
输出格式
一行一个数表示答案(对 1×109+7 取模)。
样例数据
Sample Input Sample Output
5 4 1
数据规模与运行资源限制
0 < m ≤ n ≤ 40
时间限制: 1s
空间限制: 256MB

个人认为这道题太水了,直接上递归代码了吧:

#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0;
int now[100]={};//now[i]表示当前枚举的时候第i只猴子所分到的板栗数 
void dfs(int mk,int sum,int Maxn)//当前已经分完的猴子数,已经分完的板栗总和,当前分完的最大数字
{ 
    if (mk>n) return;
    if (sum>m) return;
    if (mk==n&&sum==m) 
    {
        ans=(ans+1)%1000000007; 
        return;
    }
    for (int i=Maxn;i<=m;i++)
        dfs(mk+1,sum+i,i);   
    return;
}
int main()
{
    freopen("monkey.in","r",stdin);
    freopen("monkey.out","w",stdout);
    cin>>m>>n;
    dfs(0,0,1);
    cout<<ans;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ronaldo7_zyb/article/details/81036947