CodeForces 126D

这道题表面上是说斐波那契数列
摘要由CSDN通过智能技术生成

       这道题表面上是说斐波那契数列,看似是一道找规律的数学题,而实际上却是一道DP题。

       大体思路:题目输入的数字很大,乍一看,好像需要求出几千位斐波那契数,实际上,只要求出87个斐波那契数就足够了。这也是这道题的第一步,求出小于等于10^18的斐波那契数,并保存在fib数组中。fib数组从1开始存储,则每个斐波那契数的下标对应它们在斐波那契数列中的位置。然后,从最大斐波那契数开始,找出一个组成n的一组斐波那契数的序号,并保存在seq数组中(详见代码)。用sort从小到大对seq排序,使得数组中的斐波那契数的下标从小到大排列,与dp数组的第一维下标对应。然后开始标准的动态规划,其中dp[i][1]表示拆分下标为seq[i]的斐波那契数时的情况数,dp[i][0]表示不拆分下标为seq[i]的斐波那契数时的情况数。初始状态,为dp[0][0]=1,dp[0][1]=(seq[0]-1)/2;状态转移方程为dp[i][0]=dp[i-1][0]+do[i-1][1],dp[i][1]=dp[i-1][0]*((seq[i]-seq[i-1]-1)/2)+dp[i-1][1]*((seq[i]-seq[i-1])/2)。要明白这个初始状态和状态转移方程,那就要明白斐波那契数列中第i个斐波那契数有几种替代方案,答案是(i-1)/2,想明白这个,上面的式子就好理解了。

       补充:这是我第一次在CF上提交代码,发现要把DEV中的“system(“PAUSE”);”去掉,否则会WA。此外大家还可以参考一下几篇大神的博文:2014工大校赛题目以及解codeforces 126D Fibonacci Sums 递推 DPCodeforces 126D Fibonacci Sums 求n由任意的Sum(fib)的方法数 dp


代码(GUN C++):

#include <iostream>
#include <algorithm>
#include <cstdio> 

#define MAX 90
using namespace std; 

__int64 fib[MAX],dp[MAX][2];    //dp[i][0]表示fib[seq[i]]不被拆分,dp[i][1]表示fib[seq[i]]被拆分 
int seq[MAX];

void init()
{
    int i; 
    fib[1]=1;
    fib[2]=2;
    for(i=3;i<MAX;i++) fib[i]=fib[i-1]+fib[i-2];
    //for(i=1;i<MAX;i++) cout<<fib[i]<<'\t';
}

int main()
{
    int i,t,c;
    __int64 n;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d",&n);
        c=0;
        for(i=MAX-1;i>0&&n!=0;i--)
        {
            if(fib[i]<=n)
            {
               seq[c++]=i;
               n-=fib[i];          
            }                 
        }        
        sort(seq,seq+c);
        //for(i=0;i<c;i++) cout<<seq[i]<<endl;
        dp[0][0]=1;
        dp[0][1]=(seq[0]-1)/2;
        for(i=1;i<c;i++)
        {
            dp[i][0]=dp[i-1][0]+dp[i-1][1];
            dp[i][1]=dp[i-1][0]*((seq[i]-seq[i-1]-1)/2)+dp[i-1][1]*((seq[i]-seq[i-1])/2);            
        }
        printf("%I64d\n",dp[c-1][0]+dp[c-1][1]);       
    }       
    //system("PAUSE");   提交CF
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值