•題解
相似與斐波那契數列;php
定義 $f[i]$ 表示從 $1$ 號蜂房走到 $i$ 號蜂房的總方案數,那麼有 $f[1]=f[2]=1$,$f[i]=f[i-1]+f[i-2]\ ,\ i > 2$;c++
但此題要求你從 $a$ 號蜂房走到 $b$ 號蜂房的總方案數;ide
那麼,你就須要將 $a$ 號蜂房設置爲 $1$ 號蜂房便可,即令 $f[a]=f[a+1]=1$,$f[i]=f[i-1]+f[i-2]\ ,\ i > a+1$;測試
輸出 $f[b]$ 便可;大數據
•Code
View Code1 #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 }
•變形
題面不變,數據增強;spa
令 $0<a<b\le 100000$,並要求最終答案對 $1e9+7$ 取模;code
•分析
對變形前代碼時間複雜度分析的話,最壞的狀況是,$O(T\cdot 50)$,固然,若是 $T < 10^6$ 仍是能夠過得;blog
可是,加大數據後,這可就不必定了;get
考慮到每次測試數據中的 $for$ 循環,可不能夠提早預處理出來;it
若是 $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
View Code1 #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 }
•題意
有排成一行的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
View Code1 #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 }
•題解
定義 $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
View Code1 #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 }