原題連接spa
這是我本身Clone的專題,A,B題解昨天發過了.net
C:參考代碼:code
/* 很容易咱們能夠手推出n = 1, 2, 3時的狀況,咱們假設前n - 1 列已經放好,方法有dp[n - 1]種,第n列很顯然有1種方法,那我 再假設前n - 2列已經放好,方法有dp[n - 2]種,此時咱們知道 第n - 1和第n列確定是橫着放的,若是他們豎着放就和前n - 1列 放好的狀況相同,因此咱們能夠推出方程dp[n] = dp[n - 1] + dp[n - 2]; */ #include <cstdio> using namespace std; typedef long long int ll; const int maxn = 50 + 5; int n; ll dp[maxn]; int main() { dp[1] = 1; dp[2] = 2; dp[3] = 3; for(int i = 4; i <= maxn; i ++) { dp[i] = dp[i - 1] + dp[i - 2]; } while(~scanf("%d", &n)) { printf("%lld\n", dp[n]); } return 0; }
D:參考代碼:blog
/* 解題思路:仍是一如既往的遞推...這個題和塗格子的那個題目很像 很容易咱們能夠手推出n = 1, 2, 3的狀況,對於第n個格子,我 們假設前n - 1個格子已經塗好了,那麼咱們知道若是第n - 1個格子 是O,那麼咱們第n個格子有兩種塗法,若是不是O,咱們第n個格子有 三種塗法,對於第n - 1個格子,咱們能夠看第n - 2個格子,若是 第n - 2個格子 */ #include <cstdio> using namespace std; typedef long long int ll; const int maxn = 40 + 5; int n; ll dp[maxn]; int main() { dp[1] = 3; dp[2] = 8; dp[3] = 22; for(int i = 4; i <= maxn; i ++) { dp[i] = 2 * (dp[i - 1] + dp[i - 2]); } while(~scanf("%d", &n)) { printf("%lld\n", dp[n]); } return 0; }
E:參考代碼:get
/* 一樣是遞推,手推出n = 2, 3時全部未中獎的狀況,咱們先把 他們抽獎假設爲放東西,那麼第n個參與者放東西時它能夠放到 任意一個前面的位置即n - 1種方法,咱們假設爲k爲n放置的坐 標,那麼咱們還須要將第k個放到其它位置,咱們知道當第k個放 到第n個位置時,其它n - 2個有dp[n - 2]種方法,當第k個不放 到第n個位置時,這n - 1個有dp[n - 1]種方法放置,因此咱們 能夠得出dp[n] = (n - 1) * (dp[n - 1] + dp[n - 2])。 */ #include <cstdio> using namespace std; typedef long long int ll; const int maxn = 20 + 5; int c, n; ll dp[maxn]; ll mather[maxn]; int main() { dp[2] = 1; dp[3] = 2; mather[2] = 2; mather[3] = 6; for(int i = 4; i <= maxn; i ++) { dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]); mather[i] = mather[i - 1] * i; } scanf("%d", &c); while(c --) { scanf("%d", &n); printf("%.2f%%\n", ((double)dp[n] * 100) / mather[n]); } return 0; }
F:參考代碼:io
/* 這個題多是上一題的增強版? 上一題是說n我的全爲選中正確的百分比,這題是求n個裏有m個全 未選中的種數,高中同窗應該都能想到選出m個讓他們全不合格就行, C(n, m) * dp[m]即爲方程了。 */ #include <cstdio> using namespace std; typedef long long int ll; const int maxn = 20 + 5; int c, n, m; ll dp[maxn], mather[maxn]; int main() { dp[2] = 1; dp[3] = 2; for(int i = 4; i <= maxn; i ++) dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]); scanf("%d", &c); while(c --) { scanf("%d %d", &n, &m); ll p = 1; for(int i = n - m + 1; i <= n; i ++) p *= i; for(int i = 1; i <= m; i ++) p /= i; printf("%lld\n", p * dp[m]); } return 0; }
G:參考代碼:class
/* 這題一開始沒有思路emm,去網上查了一下發現受益不淺。 參考直線相交,咱們發現每增長一條直線就會增長n - 1個交點, 就會增長n個平面,因此咱們知道對於直線相交產生的平面個數有 dp[n] = dp[n - 1] + n; 對於折線呢,咱們發現,每畫一條折線咱們老是能和以前的n - 1 條折線多出4個交點,即總共多出4 * (n - 1) 個交點,那麼就多出了 4 * (n - 1) + 1個面,就能夠得出遞推方程dp[n] = dp[n - 1] + 4 * [n - 1] + 1 對於Z型折線,畫一畫就能夠知道每增長一條z型折線,最多能與原圖的n - 1條z型折線 共多生成9 * (n - 1) 個交點,也便可以獲得遞推方程爲 dp[n] = dp[n - 1] + 9 * (n - 1) + 1; */ #include <cstdio> using namespace std; typedef long long int ll; const int maxn = 10000 + 5; int c, n; ll dp[maxn]; int main() { dp[1] = 2; for(int i = 2; i <= maxn; i ++) { dp[i] = dp[i - 1] + 4 * (i - 1) + 1; } scanf("%d" ,&c); while(c --) { scanf("%d", &n); printf("%lld\n", dp[n]); } return 0; }