• Codeforces-126D. Fibonacci Sums


    传送门

    T组数组,求对于每个数,有多少种表示成不同斐波那契数的和的方法。

    e.g. 13=13=5+8=2+3+8

    首先,每个数是肯定可以表示成斐波那契数类的和的,我们将数用01串表示,1代表取第i位斐波那契数。例如13表示成100000,4表示成101.

    同时13也可以表示成11000。即一个1可以拆成低一位和低两位的1。

    这里要注意两个个性质

    1、第n位的1进行拆分(如果可以拆分)时,第n-1必然是1.这可以由(111111==1010100和11111==101001看出)

    2、诸如10000的形式(1后面接n个零),他有[n/2]+1种表示形式,其中将一个1拆分了的形式有[n/2]种

    那么我们先预处理,得知10^18范围内我们需要求取88个斐波那契数。然后将每个数表示成斐波那契进制形式,用数组seq[]存储,再进行dp

    用两个数组进行dp。dp[i][1]表示保留seq[]第n位数进行表示,dp[i][0]表示不保留seq[]第n位斐波那契,选择将它拆分

    显然dp[i][1]=dp[i - 1][1] + dp[i - 1][0];

    那么考虑dp[i][0]由什么转移得来

    如果seq[]中第i-1位的1拆分了,由性质1知二者的间隔0的数目为seq[i]-seq[i-1],否则位seq[i]-seq[i-1]-1。再由性质2知第i位的1可以拆分成的数目。然后根据乘法原理,就得到转移式dp[i][0]=seq[i] - seq[i - 1] - 1) / 2 * dp[i - 1][1] + (seq[i] - seq[i - 1]) / 2 * dp[i - 1][0]

    (注意上式子中的除二运算是向下取整,所以要先除再乘,一开始这里写错了...)

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 #define INF 0x3f3f3f3f
     6 using namespace std;
     7 typedef long long LL;
     8 const int maxn = 88;
     9 
    10 LL fib[maxn + 2];
    11 LL dp[maxn + 2][2];
    12 int seq[maxn + 2];
    13 
    14 int main() {
    15     fib[1] = 1;
    16     fib[2] = 2;
    17     for (int i = 3; i <= maxn; i++) {
    18         fib[i] = fib[i - 1] + fib[i - 2];
    19     }
    20     int T;
    21     scanf("%d", &T);
    22     LL N;
    23     while (T--) {
    24         scanf("%lld", &N);
    25         memset(seq, 0, sizeof(seq));
    26         int cnt = 0;
    27         for (int i = maxn; i >= 1; i--) {
    28             if (N >= fib[i]) {
    29                 N -= fib[i];
    30                 seq[cnt++] = i;
    31             }
    32         }
    33         reverse(seq, seq + cnt);
    34         dp[0][1] = 1;
    35         dp[0][0] = (seq[0] - 1) / 2;
    36         for (int i = 1; i < cnt; i++) {
    37             dp[i][1] = dp[i - 1][0] + dp[i - 1][1];
    38             dp[i][0] = (seq[i] - seq[i - 1] - 1) / 2 * dp[i - 1][1]
    39                      + (seq[i] - seq[i - 1]) / 2 * dp[i - 1][0];
    40         }
    41         printf("%lld
    ", dp[cnt - 1][0] + dp[cnt - 1][1]);
    42     }
    43 
    44     return 0;
    45 }
  • 相关阅读:
    oracle数据库中的单行函数
    Oracle数据库的基本语句
    oracle数据库安装的注意事项
    第一个自动化脚本
    负载均衡__笔记
    计算机名词解释
    开发规范__笔记
    索引_笔记
    主从复制_笔记
    Eclipse Git和sourceTree用法
  • 原文地址:https://www.cnblogs.com/xFANx/p/8419959.html
Copyright © 2020-2023  润新知