zoukankan      html  css  js  c++  java
  • UESTC_菲波拉契数制升级版 2015 UESTC Training for Dynamic Programming<Problem L>

    L - 菲波拉契数制升级版

    Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
     

    我们定义如下数列为菲波拉契数列:

    F(1)=1

    F(2)=2

    F(i)=F(i1)+F(i2)(i>=3)

    给定任意一个数,我们可以把它表示成若干互不相同的菲波拉契数之和。比如13有三种表示法

    13=13

    13=5+8

    13=2+3+8

    现在给你一个数n,请输出把它表示成若干互不相同的菲波拉契数之和有多少种表示法。

    Input

    第一样一个数T,表示数据组数,之后T行,每行一个数n

    T105

    1n1018

    Output

    输出T行,每行一个数,即n有多少种表示法。

    Sample input and output

    Sample InputSample Output
    6
    1
    2
    3
    4
    5
    13
    
    1
    1
    2
    1
    2
    3

    解题思路:

    首先高位到低位贪心得到基础情况(最好,因为留了最多的操作空间)

      dp(i,j) 表示正在决策第 i 位 ( 后面的已经决策完毕 ),且是否取 0->不取,1->取

      dp(i,1) = dp(i-1,0) + dp(i-1,1) //取,转移到i-1

      不取,那么这一位斐波那契由前面的相加得到

         前面一位取了: 因为不能有相同,所以只能分解成 (x-1) / 2 (少了个0) 种情况( x 是前面0的个数 ) -> 00001  -- 00110 -- 11010

         前面一位没取: 因为不能有相同,所以只能分解成 x / 2 种情况.

      dp(i,0) = dp(i-1,1) *(A-1) + dp(i-1,0) * A;

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #define pb push_back
    typedef long long ll;
    using namespace std;
    const int maxn = 100;
    ll f[maxn];
    int dp[maxn][2];
    vector<int>st;
    
    void init_f()
    {
       f[0] = 0 , f[1] = 1 , f[2] = 2;
       for(int i = 3 ; i <= 90 ; ++ i)
        f[i] = f[i-1] + f[i-2];
    }
    
    
    
    int main(int argc , char *argv[])
    {
      init_f();
      int Case;
      scanf("%d",&Case);
      while(Case--)
       {
             st.clear();
             memset(dp,0,sizeof(dp));
             ll beg;
             scanf("%lld",&beg);
             int pos = 88;
             while(beg)
              {
                    if (beg >= f[pos]) // Choose
                     {
                        st.pb(pos);
                  beg -= f[pos];
               }
              pos--;
           }
          st.pb(0);
          reverse(st.begin(),st.end()); //高位到低位dp 
          dp[0][1] = 1; //初始化最高位取1有一种情况.
          for(int i = 1 ; i < st.size() ; ++ i)
           {
                 dp[i][1] = dp[i-1][0] + dp[i-1][1];
                 int zeronum = st[i] - st[i-1] ;
                 dp[i][0] = dp[i-1][1] * ( (zeronum-1) / 2 ) + dp[i-1][0] * (zeronum / 2); //注意加括号,不然出问题! 
           }
          printf("%d
    ",dp[st.size()-1][0] + dp[st.size()-1][1]);
       }
      return 0;
    }
  • 相关阅读:
    LVS的优点和缺点
    linux系统中如何查看日志 (常用命令)
    linux隐藏病毒处理(top查询us占用70%左右,却没有CPU高使用的进程)
    linux系统批量注释的方法
    linux系统硬件时间命令
    LINUX服务器设置只允许密钥登陆
    linux系统脚本放在后台与前台
    Kworkerd恶意挖矿分析
    HAProxy的优点
    find命令
  • 原文地址:https://www.cnblogs.com/Xiper/p/4539642.html
Copyright © 2011-2022 走看看