1. 程式人生 > >HDU入門遞推專題

HDU入門遞推專題

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;
} 

HDU2050折線分割平面

題解:https://blog.csdn.net/qq_40922859/article/details/81452148

PS:想要研究的更新,可以去看《組合數學》第一章。