HDU入門遞推專題
阿新 • • 發佈:2018-12-09
HDU2044一隻小蜜蜂...
題解:考慮當你在第N個蜂房時,是從前面的那一步過來的,就很好理解了;
繼續考慮任何從a到b的路徑都可以轉化成1-b-a+1的路徑;
繼續觀察f[1] = 0;f[2] = 1;f[3] = 2;f[4]=3......斐波那契數列;
從而可得f[n] = f[n-1]+f[n-2].
AC程式碼:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 60; typedef long long ll; ll a[maxn]; void Init() { a[0] = 0; a[1] = 1; a[2] = 1; for(int i = 3; i <= 60; i++) a[i] = a[i-1]+a[i-2]; } int main(void) { Init(); int t; cin>>t; while(t--) { int x,y; cin>>x>>y; cout<<a[y-x+1]<<endl; } return 0; }
HDU2045不容易系列之(3)—— LELE的RPG
題解:考慮最後一個方格,如果f[n-1]的顏色和第一個相同,那麼最後一個方格有兩種染法,由分步乘法原理可得f[n] = f[n-2]2;
如果f[n-1]的顏色和第一個不相同,那麼最後一個方格只有一個放法,繼續考慮分步乘法,
**f[n]=f[n-1]*1;所以綜合可得,f[n] = f[n-1]+2**f[n-2].
AC程式碼:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 50+5; typedef long long ll; ll f[maxn]; void Init() { f[0] = 0; f[1] = 3; f[2] = 6; f[3] = 6; for(int i = 4; i <= 50; i++) { f[i] = f[i-1] + 2*f[i-2]; } } int main(void) { Init(); int n; while(cin>>n) { cout<<f[n]<<endl; } return 0; }
HDU2046骨牌鋪方格
題解:考慮第n個格,由前面的決定
1:先鋪好n-1個格,有f(n-1)個方法,再鋪第n層的時候只有一種方法,橫著鋪,所以總方法是1*f(n-1);
2: 先鋪好n-2格,有f(n-2)個方法,再鋪後面兩層的時候只能兩個都豎著鋪(否則與第一種情況重複),所以也只有一種。
所以:綜上f[n] = f[n-1]+f[n-2];
AC程式碼:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 50+5; ll f[maxn]; void Init() { f[0] = 0; f[1] = 1; f[2] = 2; f[3] = 3; for(int i = 3; i <= 50; i++) { f[i] = f[i-1]+f[i-2]; } } int main(void) { Init(); int n; while(cin>>n) { cout<<f[n]<<endl; } return 0; }
HDU2047阿牛的EOF牛肉串
題解:考慮最後一個字元的情況,只有三種E,O,F.
當O不是最後一個字元時,顯然倒數第二個不能是O,只有兩種情況,因此考慮分步乘有f[n] = 2*f[n-1]
當O是最後一個字元時,那麼第n-1個不能為O,此情況有f[n] = 2*f[n-2];
綜上:f[n] = (f[n-1]+f[[n-2]])*2
AC程式碼:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 50;
typedef long long ll;
ll a[maxn];
void Init()
{
a[0] = 0;
a[1] = 3;
a[2] = 8;
for(int i = 3; i <= 50; i++)
{
a[i] = 2*(a[i-1]+a[i-2]);
}
}
int main(void)
{
Init();
int t;
while(cin>>t)
{
cout<<a[t]<<endl;
}
return 0;
}
HDU2048神、上帝以及老天爺
題解:分母是最容易想到的是N!,分母是錯排公式。為什麼呢?
錯排公式引入:
十本不同的書放在書架上。現重新擺放,使每本書都不在原來放的位置。有幾種擺法?這個問題推廣一下,就是錯排問題,是組合數學中的問題之一。考慮一個有n個元素的排列,若一個排列中所有的元素都不在自己原來的位置上,那麼這樣的排列就稱為原排列的一個錯排。 n個元素的錯排數記為D(n)。 研究一個排列錯排個數的問題,叫做錯排問題或稱為更列問題。錯排問題最早被尼古拉·伯努利和尤拉研究,因此歷史上也稱為伯努利-尤拉的裝錯信封的問題。這個問題有許多具體的版本,如在寫信時將n封信裝到n個不同的信封裡,有多少種全部裝錯信封的情況?又比如四人各寫一張賀年卡互相贈送,有多少種贈送方法?自己寫的賀年卡不能送給自己,所以也是典型的錯排問題。
簡單推理:
當n個編號元素放在n個編號位置,元素編號與位置編號各不對應的方法數用D(n)表示,那麼D(n-1)就表示n-1個編號元素放在n-1個編號位置,各不對應的方法數,其它類推.
第一步,把第n個元素放在一個位置,比如位置k,一共有n-1種方法;
第二步,放編號為k的元素,這時有兩種情況:⑴把它放到位置n,那麼,對於剩下的n-1個元素,由於第k個元素放到了位置n,剩下n-2個元素就有D(n-2)種方法;⑵第k個元素不把它放到位置n,這時,對於這n-1個元素,有D(n-1)種方法;
綜上得到D(n) = (n-1) [D(n-2) + D(n-1)]
特殊地,D(1) = 0, D(2) = 1.
------------摘自百度百科
AC程式碼:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 20;
double a[maxn];
double b[maxn];
void Init()
{
a[1] = 0.00;
a[2] = 1.00;
b[2] = 2.00;
for(int i = 3; i <= maxn; i++)
{
a[i] = (i-1)*(a[i-1]+a[i-2]);
b[i] = b[i-1]*i;
}
}
int main(void)
{
Init();
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
printf("%.2lf%%\n",a[n]/b[n]*100);
}
return 0;
}
HDU2049不容易系列(4)---考新郎
題解:對比HDU2048,相當於從N箇中選取M個進行錯排
AC程式碼:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long f[25];
int main(void)
{
int n;
scanf("%d",&n);
while(n--)
{
int a,b;
scanf("%d%d",&a,&b);
f[1] = 0;
f[2] = 1;
for(int i = 3; i <= 20; i++)
f[i] = (i-1)*(f[i-1]+f[i-2]);
long long sum1 = 1;
long long sum2 = 1;
for(int i = a; i > a-b; i--)
sum1 *= i;
for(int i = 2; i <= b; i++)
sum2 *= i;
printf("%lld\n",sum1/sum2*f[b]);
}
return 0;
}