bzoj 2660: [Beijing wc2012]最多的方案
Time Limit: 5 Sec Memory Limit: 128 MB
[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; }
我爱学习,学习使我快乐