最长斐波那契子序列选取(离散化 + 二分 + DP)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长斐波那契子序列选取(离散化 + 二分 + DP)相关的知识,希望对你有一定的参考价值。


 

 

 

[题目]:

  • 如果对于所有的i = 3,4,..,n,有 ai =  ai-1+ ai-2, 那么整数序列a1,a2,...,an 就被称作Fibonacci数列。

    给出一个整数数列 c1, c2, ..., cm,你需要找出这个数列里的最长Fibonacci子序列(注意,子序列不能改变给出的整数数列顺序)。

  • 输入
  • 输入数据第一行包含一个整数m(1 <= m <= 3,000)。其后一行有m个整数,这些整数的绝对值不超过10^9。 
  • 输出
  • 仅输出一个整数,表示输入数据给出的序列中的最长Fibonacci子序列的长度。 
  • 样例输入
  • 10
    1 1 3 -1 2 0 5 -1 -1 8
    
  • 样例输出
  • 5

[思路] 任意一个斐波那契数列确定其中连续的两项,即可确定这个数列中所有的项,也就是可以确定长度。设定数组dp[i][j]表示下标为 i  和  j 的数字是某一个飞播拉切数列的后两项,那么有状态转移方程    dp[j][k] = max(dp[j][k] , dp[i][j]+1) 当 a[i] + a[j] = a[k] 且 k > j .  某一个数字可以出现多次,我们可以算出a[k]的值,但我们不知道a[k]出现在哪些位置,如果我们把大于j的所有位置全部搜索,复杂度反而升高了。所以离散化处理以后二分查找,离散化以后,数字最大也就是3000可以储存在一个vector数组里,储存当前数字出现的所有位置。然后每次二分查找。最后筛序里面位置大于当前j的位置的点进行转移。

[代码君]

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <string.h>
 5 using namespace std;
 6 const int maxn = 3010;
 7 int dp[maxn][maxn];
 8 int a[maxn] ;
 9 int check[maxn];
10 int encode[maxn];
11 int n;
12 int key;
13 vector<int> num[maxn];
14 int bin(int aim)
15 {
16     int l = 1 , r = key - 1;
17     int mid;
18     while(l <= r)
19     {
20         mid = (l + r) / 2;
21         if(aim == encode[mid]) break;
22         else if(aim == encode[l]) {mid = l ; break;}
23         else if(aim == encode[r]) {mid = r ; break;}
24         else if(encode[mid] > aim) r = mid - 1;
25         else if(encode[mid] < aim) l = mid + 1;
26     }
27     return l <= r ? mid : -1;
28 }
29 
30 int slove()
31 {    
32     memset(dp , 0 , maxn * maxn * sizeof(int));
33     for(int i = 1 ; i <= n ; i++){ cin >> a[i] ; check[i] = a[i];}
34     if(n == 1) return 1;
35     if(n == 2) return 2;
36     sort(check + 1 , check + 1 + n);
37     int pre = check[1];
38     encode[1] = check[1];
39     for(int i = 1 ; i <= n ; i++) if(a[i] == check[1]) num[1].push_back(i);
40     key = 2;
41     for(int i = 2 ; i <= n ; i++)
42     {
43         if(check[i] == pre) continue;
44         for(int j = 1 ; j <= n ; j++) if(a[j] == check[i]) num[key].push_back(j);
45         encode[key++] = check[i];
46         pre = check[i];
47     }
48     int ans = 0;
49     for(int i = 1 ; i < n ; i++)
50     {
51         for(int j = i + 1 ; j <= n ; j++)
52         {
53             int next = a[i] + a[j];
54             
55             int pos = bin(next);
56             
57             if(pos < 0) continue;
58             else
59             {
60                 
61                 for(int k = 0 ; k < num[pos].size() ; k++)
62                 {
63 
64                     int temp = num[pos][k];
65                     if(temp <= j) continue;
66                     dp[j][temp] = max(dp[j][temp],dp[i][j] + 1);
67                     ans = max(ans , dp[j][temp]);
68                 }
69             }
70         }
71     }
72 
73 
74     return ans + 2;
75 }
76 
77 int main()
78 {
79     while(cin >> n)
80     {
81         int ans = slove();
82         cout << ans << endl;
83     }
84     return 0;
85 }

 

以上是关于最长斐波那契子序列选取(离散化 + 二分 + DP)的主要内容,如果未能解决你的问题,请参考以下文章

每日一题873. 最长的斐波那契子序列的长度

LeetCode 0873.最长的斐波那契子序列的长度

873. 最长的斐波那契子序列的长度

LeetCode 873. 最长的斐波那契子序列的长度

LeetCode 873 最长的斐波那契序列的长度[双指针 二分法 动态规划 Map] HERODING的LeetCode之路

最长斐波那契序列-LeetCode-873