hihocoder1239分析

一、題意分析

給定一個n個數的數列,求其中的前綴斐波那契子串的個數對1000000007取模的值。例如:對于數列a{a1~a6}:
2 1 1 2 2 3

{a2}: 1
{a3}: 1
{a2, a3}: 1 1
{a2, a3, a4}: 1 1 2
{a2, a3, a5}: 1 1 2
{a2, a3, a4, a6}: 1 1 2 3
{a2, a3, a5, a6}: 1 1 2 3
有7個前綴斐波那契子串,解為7。

n<=1000000, 0<=ai<=100000

二、算法分析:

第一反應是動態規劃。但是看到n的范圍達到了106,感覺有點怕MLE。后來看到了ai的范圍是105。而fibonacci數列第25項為75025,10^6*25的int數組還是可以開下的。

所以就定義轉移方程如下:

f(i, j)表示當前在從ai取到an,當前正在取的是fibonacci數列的第j位。f(0, 0)即為所求。

當a[i] = fibonacci[j],也就是當前的ai正好是fibonacci數列的第j位的時候,我們有兩個選擇,取當前的ai:
這個操作用轉移方程表示就是f(i+1, j+1)
或者不取,就是f(i+1, j)
那么f(i, j)就等于兩種取法相加的和,f(i, j) = f(i+1, j+1) + f(i+1, j)

如果當前的值不能取,也就是a[i] != fibonacci[j],那么只有不取的情況,f(i, j) = f(i+1, j)。為了防止在加法過程中存爆,此處相加后應mod 1000000007。

接下來就是邊緣判定:也就是j>=25以及i>=n的情況。由于都已經取完無法再取,那么這種情況下的f(i, j)的值就是1。
需要特別注意的是f(n, 0)應當等于0。按照它的含義,取到第n項(因為數組下標從0開始,所以第n項已經超出了),當前取的還是第0位,也就是第0位還沒取!所以這個不應當成為一個解,f(n, 0)=0!

三、程序框架

先讀入,data清-1,data[n][0]取0,然后DP求解f(0, 0)即可。

#include <stdio.h>

const int fibonacci[25] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025};
int a[1000000];
unsigned int data[1000001][26];
int n;

void trydp(int i, int j)
{
    if ((i >= n) || (j >= 25))
    {
        data[i][j] = 1;
        return;
    }
    if (data[i + 1][j] == -1)
        trydp(i + 1, j);
    data[i][j] = data[i + 1][j];
    if (a[i] == fibonacci[j])
    {
        if (data[i + 1][j + 1] == -1)
            trydp(i + 1, j + 1);
        data[i][j] = (data[i][j] + data[i + 1][j + 1]) % 1000000007;
    }
}

int main()
{
    scanf("%d", &n);
    int i, j;
    for (i=0; i<n; ++i)
        scanf("%d", &a[i]);

    long ans = 0;
    for (i=0; i<=n; ++i)
        for (j=0; j<=26; ++j)
            data[i][j] = -1;
    data[n][0] = 0;

    trydp(0, 0);
    printf("%d\n", data[0][0]);

    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容