這道題裸的dp方程應該可以寫的出來,我記錄的狀態如下:
dp[i][j]表示以a[i]為第一個元素,a[j]為第二個元素的斐波那契序列的最大長度,這樣i<=j<br />轉移方程:<br />dp[i][j]=dp[j][k]+1,其中a[k]=a[i]+a[j]<br />從後向前掃描,每次更新dp值後更新最大長度以及第一第二項,最後的答案直接根據第一第二項迭代即可<br />
現在遇到的最大問題就是轉移,裸的轉移是O(n)的,直接從前向後掃一遍,找到第一個合格k,這樣總的複雜度是枚舉加上掃描,是O(n^3)的,明顯對n為3000的資料來說太大了,不可取。
後來想到了二叉樹,嗯,就是map,在樹中維護值為x的最前位置,這樣直接通過在樹中找a[i]+a[j]的最前位置即可,後來想想也不對,複雜度是O(n^2*logn)的,對於STL的大常數不放心,算了一下3000^2*log3000差不多10^8數量級,會TLE。又開始想轉移能不能壓縮。
最後想到hash的辦法,因為轉移無非就是在一個序列中找一個x對應的最前位置,直接將x進行hash,對應的hash值的位置存放我們要的x對應的最前位置即可。
hash函數亂寫的- -
發現其實資料重複的機率不大,沒有最佳化,直接用了。。。
這樣可以在近似O(1)的時間內找到我們要的值,轉移加上枚舉就是O(n^2)的了
My Code:
#include <cstdio><br />#include <cstring><br />#include <cstdlib><br />#include <algorithm></p><p>using namespace std;</p><p>const int MAX=100000;<br />const int mod=100007;<br />struct hbox<br />{<br />int st;<br />hbox* s;<br />}hash[MAX],*h[mod],*cur;<br />int cnt[mod],pos;</p><p>unsigned int BKDHash(int s)<br />{<br />unsigned int r=abs(s);<br />return (r*r&0x7FFFFFFF)%mod;<br />}</p><p>bool has(int s,int& pos)<br />{<br />int d=BKDHash(s);<br />hbox* p=h[d];<br />while(p)<br />{<br />if(s==p->st){<br />pos=p-hash;<br />return true;<br />}<br />p=p->s;<br />}<br />return false;<br />}</p><p>void insert(int s,int v)<br />{<br />int d=BKDHash(s);<br />hbox* p=h[d];<br />while(p)<br />{<br />if(s==p->st){<br />cnt[p-hash]=v;<br />return;<br />}<br />p=p->s;<br />}<br />cur->st=s;<br />cur->s=h[d];<br />h[d]=cur++;<br />cnt[cur-hash-1]=v;<br />}</p><p>void init(){<br />memset(h,0,sizeof(h));<br />cur=hash;<br />}</p><p>int a[3100];<br />short dp[3100][3100];</p><p>int main(){<br />int n;<br />int x,y,pos;<br />bool blocks=false;<br />int ret;</p><p>while(~scanf("%d",&n)){<br />if(blocks){<br />puts("");<br />}else{<br />blocks=true;<br />}<br />init();<br />for(int i=0;i<n;i++){<br />scanf("%d",&a[i]);<br />}</p><p>for(int i=0;i<n;i++){<br />for(int j=i+1;j<n;j++){<br />dp[i][j]=1;<br />}<br />}</p><p>x=a[0];<br />ret=0;<br />for(int j=n-1;j>=0;j--){<br />for(int i=j-1;i>=0;i--){<br />if(has(a[i]+a[j],pos)){<br />dp[i][j]=dp[j][cnt[pos]]+1;<br />}<br />if(dp[i][j]>ret){<br />x=a[i];<br />y=a[j];<br />ret=dp[i][j];<br />}<br />}<br />insert(a[j],j);<br />}</p><p>printf("%d/n",ret+1);<br />printf("%d",x);<br />for(int i=0;i<ret;i++){<br />printf(" %d",y);<br />swap(x,y);<br />y+=x;<br />}<br />puts("");<br />}</p><p>return 0;<br />}</p><p>