c/c++语言开发共享洛谷P4133 [BJOI2012]最多的方案(记忆化搜索)

题意 题目链接 求出把$n$分解为斐波那契数的方案数,方案两两不同的定义是分解出来的数不完全相同 Sol 这种题,直接爆搜啊。。。 打表后不难发现$<=1e18$的fib数只有88个 最先想到的应该是直接把$n$加入到搜索状态里,然后枚举能被分成哪些 但是这样分解出来的数可能会有重复的,因此我们还要 …


题意

题目链接

求出把$n$分解为斐波那契数的方案数,方案两两不同的定义是分解出来的数不完全相同

sol

这种题,直接爆搜啊。。。

打表后不难发现$<=1e18$的fib数只有88个

最先想到的应该是直接把$n$加入到搜索状态里,然后枚举能被分成哪些

但是这样分解出来的数可能会有重复的,因此我们还要把当前考虑到第几个数也加入到状态里。

不难得到以下代码

洛谷P4133 [BJOI2012]最多的方案(记忆化搜索)

但是很显然会t飞。

优化一下,只考虑当前的fib数对答案的贡献,

也就是搜两种情况:

1、用该数分解

2、不用该数分解

代码是这样的

洛谷P4133 [BJOI2012]最多的方案(记忆化搜索)

然而还是会t飞。

继续剪枝。

根据斐波那契的性质$sum_{i = 1}^n f_i = f_{n+2} -1$

因此我们想要用前$ti – 1$个合成$x$,必须满足$x < f_{ti+1}$。

然后就a了qwq

// luogu-judger-enable-o2  #include<cstdio>  #include<iostream>  #include<map>  #define pair pair<int, int>  #define mp(x, y) make_pair(x, y)  #define fi first  #define se second   #define int long long  #define ull unsigned long long    using namespace std;  const int maxn = 1e5 + 10;  inline int read() {      char c = getchar(); int x = 0, f = 1;      while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}      while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();      return x * f;  }  int f[maxn], tot, lim, dp[maxn], n;  map<pair, int> mp;  int dfs(int x, int ti) {      if(mp.find(mp(x, ti)) != mp.end()) return mp[mp(x, ti)];      if(x == 0) return 1;      int ans = 0;      /*for(int i = ti; i >= 1; i--) {          if(x - f[i] >= 0) ans += dfs(x - f[i], i - 1);          //else break;      }*/      if(x - f[ti] >= 0) ans += dfs(x - f[ti], ti - 1);      if(x < f[ti + 1])           ans += dfs(x, ti - 1);            return mp[mp(x, ti)] = ans;  }  main() {      lim = 1e18;      f[1] = 1; f[2] = 2;      for(int i = 3; i; i++) {          f[i] = f[i - 1] + f[i - 2];          if(f[i] > lim) {tot = i; break;}      }      n = read();      //dp[0] = 1;      cout << dfs(n, tot - 1);      return 0;  }

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/607792.html

(0)
上一篇 2021年5月14日
下一篇 2021年5月14日

精彩推荐