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\n", dp[cnt - 1][0] + dp[cnt - 1][1]);
42     }
43 
44     return 0;
45 }

 

转载于:https://www.cnblogs.com/xFANx/p/8419959.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值