bzoj 2660: [Beijing wc2012]最多的方案

                   Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 617  Solved: 361
[Submit][Status][Discuss]

Description

       第二关和很出名的斐波那契数列有关,地球上的OIer都知道:F1=1, F2=2, Fi = Fi-1 + Fi-2,每一项都可以称为斐波那契数。现在给一个正整数N,它可以写成一些斐波那契数的和的形式。如果我们要求不同的方案中不能有相同的斐波那契数,那么对一个N最多可以写出多少种方案呢?

Input

       只有一个整数N。

Output

       一个方案数

Sample Input

16

Sample Output

4

HINT

 



Hint:16=3+13=3+5+8=1+2+13=1+2+5+8

对于30%的数据,n<=256

对于100%的数据,n<=10^18


直接记忆化搜索就行了,fibo(88)就已经>=10^18。
设g(x,y)为考虑前x个斐波那契数的和为y的方案数。
答案即为g(87,n)。
转移的时候可以剪枝:
1.当y<=f[x]的时候可以转移到g(x-1,y-f[x)。
2.当y<f[x+1]的时候才可以转移到g(x-1,y)。

解释一下第二个,因为斐波那契数列有注明前缀和公式 f(1)+f(2)+...+f(x)=f(x+2)-1  (证明可以考虑分
奇偶添补),所以当y>=f[x+1]的时候,g(x-1,y)一定是0了,不用再转移了。

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
map<ll,ll> mmp[105];
ll n,m,k,f[105];

ll dp(int x,ll lef){
    if(!lef) return 1;
    if(x==2){
        if(lef==1) return 1;
        return 0;
    }
    
    if(mmp[x][lef]) return mmp[x][lef];
    ll ans=0;
    if(lef>=f[x]) ans+=dp(x-1,lef-f[x]);
    if(lef<f[x+1]) ans+=dp(x-1,lef);
    
    mmp[x][lef]=ans;
    return ans;
}

int main(){
    scanf("%lld",&n);
    f[1]=f[2]=1; int i;
    for(i=3;(f[i]=f[i-1]+f[i-2])<=n;i++);
    
    printf("%lld\n",dp(i-1,n));
    return 0;
}

 

posted @ 2018-01-11 18:51  蒟蒻JHY  阅读(257)  评论(0编辑  收藏  举报