最长斐波那契子序列选取(离散化 + 二分 + 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 }
时间: 2024-11-29 01:08:57

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

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

英文版A sequence X_1, X_2, ..., X_n is fibonacci-like if: - n >= 3- X_i + X_{i+1} = X_{i+2} for all i + 2 <= n Given a strictly increasing array A of positive integers forming a sequence, find the length of the longest fibonacci-like subsequence of A.

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

class Solution: def lenLongestFibSubseq(self, A: List[int]) -> int: s = set(A) n = len(A) result = 0 for i in range(n-1): for j in range(i+1, n): a, b = A[i], A[j] count = 2 while a+b in s: a, b = b, a+b count += 1 # A= [1,2,3,4,5,6,7,8] # [1,2,3,5,8

"二分查找(Binary Search)"与"斐波那契查找(Fibonacci Search)"

首先,我们来看一个笔者的拙作,一段二分查找代码 //返回值是key的下标,如果A中不存在key则返回-1 template <class T> int BinSearch(T* A, const T &key, int lo, int hi) {     int mid;     while(lo<hi)     {         mid = lo + (hi-lo)/2;         if(key < A[mid])             hi = mid-1;

快速幂--斐波那契数列

1)编写程序,求解a^b.其中b是正整数. 方法1. //一般求幂算法,O(r) public static long power1(int a,int r){ if(r<0) { System.out.println("r must be positive number!"); return -1; } if(r==0){ return 1; } long res=1; for(int i=1;i<=r;++i){ res*=a; } return res; } 这种使用

数据结构(六)查找---有序表查找(三种查找方式:折半,插值,斐波拉契查找)

前提 有序表查找要求我们的数据是有序的,是排序好的,我们只需要进行查找即可 我们下面将介绍折半查找(二分查找),插值查找,斐波那契查找 一:折半查找 (一)定义 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. (二)查找过程 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关

Project Euler 104:Pandigital Fibonacci ends 两端为全数字的斐波那契数

Pandigital Fibonacci ends The Fibonacci sequence is defined by the recurrence relation: F[n] = F[n-1] + F[n-2], where F[1] = 1 and F[2] = 1. It turns out that F541, which contains 113 digits, is the first Fibonacci number for which the last nine digi

斐波那契查找原理详解与实现

最近看见一个要求仅使用加法减法实现二分查找的题目,百度了一下,原来要用到一个叫做斐波那契查找的的算法.查百度,是这样说的: 斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的.他要求开始表中记录的个数为某个斐波那契数小1,即n=F(k)-1;  开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种  1)相等,mid位置的元素即为所求  2)>   ,low=mid+1,k-=2;说明:low=mid+1说明待查找的元素在

在c#中编写斐波拉契数列程序

思路:首先因为输出的是一个数列,又因为不定长,所以要见一个集合来装数列,其次确定第一个数和第二个数都为1,然后根据斐波拉契数列的特点,确定是一个循环语句,再根据从第三位开始,每个数字都是前两个数的和的特点写出代码.代码如下: while(true){Console.Write("请输入斐波拉契数列的长度:");int len = int.Parse(Console.ReadLine());int[] array = new int[len];if (len < 3){Consol

算法学习笔记 递归之 快速幂、斐波那契矩阵加速

递归的定义 原文地址为:http://blog.csdn.net/thisinnocence 递归和迭代是编程中最为常用的基本技巧,而且递归常常比迭代更为简洁和强大.它的定义就是:直接或间接调用自身.经典问题有:幂运算.阶乘.组合数.斐波那契数列.汉诺塔等.其算法思想: 原问题可分解子问题(必要条件): 原与分解后的子问题相似(递归方程): 分解次数有限(子问题有穷): 最终问题可直接解决(递归边界): 对于递归的应用与优化,直接递归时要预估时空复杂度,以免出现用时过长或者栈溢出.优化递归就是以