把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷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;//直接输出
}
posted @ 2020-10-22 13:53  TheLostWeak  阅读(65)  评论(0编辑  收藏  举报