最长斐波那契子序列选取(离散化 + 二分 + 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)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 873 最长的斐波那契序列的长度[双指针 二分法 动态规划 Map] HERODING的LeetCode之路