首页 > 技术文章 > 递推

violet-acmer 2019-11-03 16:41 原文

 

 

HDU 2044 "一只小蜜蜂"

•题解

  类似与斐波那契数列;

  定义 $f[i]$ 表示从 $1$ 号蜂房走到 $i$ 号蜂房的总方案数,那么有 $f[1]=f[2]=1$,$f[i]=f[i-1]+f[i-2]\ ,\ i > 2$;

  但此题要求你从 $a$ 号蜂房走到 $b$ 号蜂房的总方案数;

  那么,你就需要将 $a$ 号蜂房设置为 $1$ 号蜂房即可,即令 $f[a]=f[a+1]=1$,$f[i]=f[i-1]+f[i-2]\ ,\ i > a+1$;

  输出 $f[b]$ 即可;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 
 5 int a,b;
 6 ll f[100];
 7 
 8 int main()
 9 {
10     int T;
11     scanf("%d",&T);
12     while(T--)
13     {
14         scanf("%d%d",&a,&b);
15         f[a]=1;
16         f[a+1]=1;
17         for(int i=a+2;i <= b;++i)
18             f[i]=f[i-1]+f[i-2];
19 
20         printf("%lld\n",f[b]);
21     }
22     return 0;
23 }
View Code

•变形

  题面不变,数据加强;

  令 $0<a<b\le 100000$,并要求最终答案对 $1e9+7$ 取模;

•分析

  对变形前代码时间复杂度分析的话,最坏的情况是,$O(T\cdot 50)$,当然,如果 $T < 10^6$ 还是可以过得;

  但是,加大数据后,这可就不一定了;

  考虑到每次测试数据中的 $for$ 循环,可不可以提前预处理出来;

  如果 $a=1$ ,那么,斐波那契数列第 $b$ 项 $f[b]$ 就是答案;

  如果 $a \noe 1$ 呢?

  我们考虑一下比之前多计算的情况;

  首先,在之前的代码中,每次都令 $g[a]=g[a+1]=1$;(为不与斐波那契 $f$ 混淆,以下将上题中的 $f$ 改为 $g$)

  也就是说,$f[a]$ 比 $g[a]$ 多计算了 $f[a]-1$ 中情况,同样,$f[a+1]$ 比 $g[a]$ 多计算了 $f[a+1]-1$ 中情况;

  定义 $x=f[a]-1\ ,\ y=f[a+1]-1$,那么,由递推式 $g[a+2]=g[a+1]+g[a]$ 可得 $f[a+2]$ 比 $g[a+2]$ 多计算了 $x+y$;

  也就是说,$f[b]$ 比 $g[b]$ 多计算的东西与 $a,b$ 之间的距离有关;

  定义 $X[i]\ ,\ Y[i]$ 分别表示从 $a$ 蜂房到 $b$ 蜂房多计算了 $X[i]$ 个 $x$ 和 $Y[i]$ 个 $y$ 值;

  那么,只需要从 $f[b]$ 中减掉就行了;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int N=1e5+50;
 5 const int MOD=1e9+7;
 6 
 7 int a,b;
 8 ll x[N];
 9 ll y[N];
10 ll f[N];
11 
12 void Init()
13 {
14     x[0]=y[1]=1;
15     y[0]=x[1]=0;
16     for(int i=2;i < N;++i)
17     {
18         x[i]=x[i-1]+x[i-2];
19         y[i]=y[i-1]+y[i-2];
20         x[i] %= MOD;
21         y[i] %= MOD;
22     }
23     f[1]=f[2]=1;
24     for(int i=3;i < N;++i)
25         f[i]=(f[i-1]+f[i-2])%MOD;
26 }
27 int main()
28 {
29     Init();
30 
31     int T;
32     scanf("%d",&T);
33     while(T--)
34     {
35         scanf("%d%d",&a,&b);
36         ll u=f[a]-1;
37         ll v=f[a+1]-1;
38         ll ans=f[b]-(u*x[b-a]%MOD+v*y[b-a]%MOD)%MOD;
39         ans=(ans+MOD)%MOD;
40 
41         printf("%lld\n",ans);
42     }
43 
44     return 0;
45 }
View Code

 

 

 


HDU 2045

•题意

  有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green) 三色涂每个格子;

  每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色;

  求全部的满足要求的涂法;

•题解(递推)

  定义 $f[i]$ 表示 $i$ 个格子的总方案数;

  假设 $f[1],f[2],\cdots ,f[i-1]$ 已经求出,如何求出 $f[i]$ 呢?

  考虑到这一点 $i$ 与 $i-1$ 不同色,同时 $i$ 与 $1$ 也不同色;

  $i$ 个格子的总方案数是不是可以分为以下两种:

  ① 第 $i-1$ 个格子与第 $1$ 个格子不同色

  ② 第 $i-1$ 个格子与第 $1$ 个格子同色

  对于情况①,已知 $f[i-1]$ 求解的是 $i-1$ 与 $1$ 不同色的总方案数,所以,情况①的答案为 $f[i-1]$;

  对于情况②,因为第 $i-1$ 个格子与第 $1$ 个格子同色,且第 $i-1$ 个格子与第 $i-2$ 个格子不同色;

  也就是说,求解第 $i-1$ 个格子与第 $1$ 个格子同色的总方案数可以转化为求解第 $i-2$ 个格子与第 $1$ 个格子不同色的总方案数;

  易得 $f[i-2]$ 就是解,又因为第 $i-1$ 个格子与第 $1$ 个格子同色,所以,第 $i$ 个格子有两种选择;

  所以情况②的总方案数为 $2\times f[i-2]$;

  所以,$f[i]=f[i-1]+2\times f[i-2]$;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int N=60;
 5 
 6 int n;
 7 ll f[N];
 8 
 9 int main()
10 {
11     f[1]=3;
12     f[2]=f[3]=6;
13     for(int i=4;i < N;++i)
14         f[i]=f[i-1]+2*f[i-2];
15 
16     while(~scanf("%d",&n))
17         printf("%lld\n",f[n]);
18 }
View Code

 


HDU 2049 "不容易系列之(4)——考新郎"

•题解

  定义 $f[i][j]$ 表示 $i$ 对新婚夫妇中,$j$ 个新郎找错新娘的总方案数;

  假设 $i-1$ 对新婚夫妇的所有新郎找错新娘的总方案数已经求出;

  那么,如果现在又来了一对新婚夫妇,如何求解这 $i$ 对新婚夫妇中所有新郎找错新娘的总方案数呢?

  以求解 $f[i][j]$ 为例;

  考虑到以下几种情况:

    • 前 $i-1$ 对新婚夫妇中有 $j$ 个新郎找不到新娘,那么,第 $i$ 个新郎一定找对了新娘
    • 前 $i-1$ 对新婚夫妇中有 $j-1$ 个新郎找不到新娘,那么,第 $i$ 个新郎势必要与前 $i-1$ 对新婚夫妇中找不到新娘的新郎互换新娘才满足 $j$ 个新郎找不到新娘的条件
    • 前 $i-1$ 对新婚夫妇中有 $j-2$ 个新郎找不到新娘,那么,第 $i$ 个新郎势必要与前 $i-1$ 对新婚夫妇中找到新娘的新郎互换新娘才满足 $j$ 个新郎找不到新娘的条件
  • 情况 1 的总方案数为 $f[i-1][j]$
  • 情况 2 的总方案数为 $f[i-1][j-1]\cdot (j-1)$,第 $i$ 个新郎与这 $j-1$ 个找不到新娘的新郎中的任意一个新郎互换新娘都可以满足条件
  • 情况 3 的总方案数为 $f[i-1][j-2]\cdot (i-j+1)$,第 $i$ 个新郎与找到新娘的新郎中的任意一个互换新娘都可以满足条件

  综上,$f[i][j]=f[i-1][j]+f[i-1][j-1]\cdot (j-1)+f[i-1][j-2]\cdot (i-j+1)$ ;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int N=21;
 5 
 6 int n,m;
 7 ll f[N][N];
 8 
 9 void Init()
10 {
11     for(int i=1;i < N;++i)
12         f[i][0]=1;
13     for(int i=2;i < N;++i)
14         for(int j=2;j <= i;++j)
15             f[i][j]=f[i-1][j]+(j-1)*f[i-1][j-1]+(i+1-j)*f[i-1][j-2];
16 }
17 int main()
18 {
19     Init();
20     int T;
21     scanf("%d",&T);
22     while(T--)
23     {
24         scanf("%d%d",&n,&m);
25         printf("%lld\n",f[n][m]);
26     }
27 }
View Code

 

推荐阅读