【洛谷4133】[BJOI2012] 最多的方案(搜索水题?)
- 给定一个正整数\(n\)。
- 现要将\(n\)表示为若干互不相同的斐波那契数之和,求方案数。
- \(n\le10^{18}\)
搜索
搜索状态可以表示为当前数为\(x\),考虑到了第\(m\)个斐波那契数(\(m\)从大到小枚举)。
由于斐波那契数增长得很快,一个直观的感觉就是暴搜状态并不多。
然后只要加上一个显然的剪枝:如果\(x\)大于前\(m-1\)个斐波那契数之和,则\(Fib(m)\)必选。
然后就过了?
代码:\(O(\)能过\()\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
using namespace std;
LL n,Fib[100],S[100];map<pair<LL,int>,LL> p;
I LL dfs(Con LL& x,CI m)//记忆化搜索
{
if(!x||!m) return !x;pair<int,int> s=make_pair(x,m);if(p.count(s)) return p[s];
if(x<Fib[m]) return p[s]=dfs(x,m-1);if(x>S[m-1]) return p[s]=dfs(x-Fib[m],m-1);//剪枝
return p[s]=dfs(x,m-1)+dfs(x-Fib[m],m-1);//暴搜
}
int main()
{
RI i;for(Fib[0]=Fib[1]=S[0]=1,S[1]=i=2;i<=87;++i) S[i]=S[i-1]+(Fib[i]=Fib[i-1]+Fib[i-2]);//预处理斐波那契数及其前缀和
return scanf("%lld",&n),printf("%lld\n",dfs(n,87)),0;//直接输出
}
待到再迷茫时回头望,所有脚印会发出光芒