题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2660
当然可以看出 选了第 i 个斐波那契数<=>选了第 i - 1 和第 i - 2 个斐波那契数;
还有一个关键是:题目给出的这个数能表示成几个斐波那契数的和<=>该数可以被用斐波那契数分解。
如果把选不选每一个斐波那契数用二进制表示的话,首先要尽量使最高位最大,才能算出最多的方案。
把第一次分解的那些斐波那契数的位置记录下来,用dp表示这些数选不选。
若选这个数,则上一个选了或者没选而分解到更小的都行;
若不选这个数,则它的方案数画一画就知道是 它与上一个分解出的数中间的0的个数 * 选上一个数 + (……0的个数+1)*不选上一个数;
我觉得自己应该好好利用斐波那契数的这个写在第一行的性质。本题怎么可能不与这有关呢?
自己考虑到“上一个数也可以不选而……”的时候就不行了,这是没有考虑到利用自己假设已经算出来的值(即“不选这个数的方案数”);还是经验不足吧。
蜜汁:注释掉的部分有什么不对?
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=1e6+5; ll n,c[N],cnt,dp[90][2],pos[N],xnt; int main() { scanf("%lld",&n); c[1]=1;c[0]=1; for(int i=2;c[i-1]<=n;i++)c[i]=c[i-1]+c[i-2],cnt=i-1; for(int i=cnt;i&&n;i--)if(c[i]<=n)n-=c[i],pos[++xnt]=i; // dp[xnt][1]=1;dp[xnt][0]=(pos[xnt]-1)/2;/ // for(int i=xnt-1;i;i--) // { // dp[i][1]=dp[i+1][0]+dp[i+1][1]; // dp[i][0]=dp[i+1][0]*(pos[i]-pos[i+1])/2+dp[i+1][1]*(pos[i]-pos[i+1]-1)/2; // } // printf("%lld",dp[1][0]+dp[1][1]); sort(pos+1,pos+xnt+1); dp[1][1]=1;dp[1][0]=(pos[1]-1)/2; for(int i=2;i<=xnt;i++) { dp[i][1]=dp[i-1][1]+dp[i-1][0]; dp[i][0]=(pos[i]-pos[i-1])/2*dp[i-1][0]+(pos[i]-pos[i-1]-1)/2*dp[i-1][1]; } printf("%lld",dp[xnt][0]+dp[xnt][1]); return 0; }