ZOJ:2672 Fibonacci Subsequence(動態規劃+hash)

題意:在給定的數組裏,尋找一個最長的序列,滿足ai-2+ai-1=ai。並輸出這個序列。

思路:

很容易想到一個DP方程

dp[i][j]=max(dp[k][i])+1. (a[k]+a[i]==a[j],1<=k&&k<i)

dp[i][j]表示序列最後兩位是a[i],a[j]時的最長長度。

這個方程狀態是O(n^2),轉移是O(n),總複雜度是O(n^3)會超時。

進一步思考會發現轉移這裏是可以優化的。實際上我們只需要知道離i最近的那個滿足a[k]+a[i]==a[j]的k就行,即最大k。

舉個例子

2 3 -1 2 1 3

當i=5,j=6,即ai=1,aj=3時,這時需要找一個ak=2的,顯然a1和a4滿足,我們會選擇a4而不是a1。因爲可以轉移到a1的狀態一定都可以轉移到a1,但能轉移到a4的狀態卻不一定都能轉移到a1,因此dp[4][5]>=dp[1][5]。這樣我們只需要在遍歷數組的時候維護數組每個數的最大的下標即可。這裏使用hash來做。

注意卡內存,要用short。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<hash_map>
#include<ext/hash_map>
using namespace std;
int a[3001];
short dp[3001][3001];
struct Hash
{
    static const int mask = 0x7fff;
    int p[32768], q[32768];
    void clear()
    {
        for (int i = 0; i <= mask; ++i)
            q[i] = -1;
    }
    int& operator[](int k)
    {
        int i = k & mask;
        for (; q[i] != -1 && p[i] != k; i = (i + 1) & mask);
        p[i] = k;
        return q[i];
    }
} hash;
int main()
{
    int n;
    bool blank=false;
    while(scanf("%d",&n)!=EOF)
    {
        if(blank) printf("\n");
        else  blank=true;
        memset(dp,0,sizeof(dp));
        hash.clear();
        for(int i=1; i<=n; ++i)
        {
            scanf("%d",&a[i]);
            for(int j=i+1; j<=n; ++j)
                dp[i][j]=1;
        }
        int ans=0,x=a[1],y;
        for(int i=n; i>=1; --i)
        {
            for(int j=i-1; j>=1; --j)
            {
                int it=hash[a[i]+a[j]];
                if(it!=-1)
                {
                    dp[j][i]=dp[i][it]+1;
                }
                if(ans<dp[j][i])
                {
                    ans=dp[j][i];
                    x=a[j];
                    y=a[i];
                }
            }
            hash[a[i]]=i;
        }
        ans++;
        printf("%d\n",ans);
        printf("%d",x);
        for(int i=2; i<=ans; ++i)
        {
            printf(" %d",y);
            int t=y;
            y=x+y;
            x=t;
        }
        printf("\n");
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章