• 最长斐波那契子序列选取(离散化 + 二分 + 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 }
  • 相关阅读:
    连分数与丢番图方程简介
    利用 random 与 tertools 模块解决概率问题
    Notepad++ 几款实用插件简介,让你的 Notepad++ 如虎添翼
    .net面试问答(大汇总)
    .net反射详解 原文://http://blog.csdn.net/wenyan07/article/details/27882363
    ASP.NET MVC4+EF5(Lambda/Linq)读取数据
    AngularJS+ASP.NET MVC+SignalR实现消息推送
    Asp.net SignalR 实现服务端消息推送到Web端
    C# Socket编程 同步以及异步通信
    C#版 Socket编程(最简单的Socket通信功能)
  • 原文地址:https://www.cnblogs.com/ticsmtc/p/5160303.html
Copyright © 2020-2023  润新知