#dp,齐肯多夫定理#CF126D Fibonacci Sums
题目
\(T(T\leq 10^5)\) 组数据,每次给定数字 \(n(n\leq 10^{18})\),
问有多少种方案将 \(n\) 分解成若干个互不相同的斐波那契数
分析
如果找到一个方案使得所有选择的斐波那契数都不相邻,
那么可以通过这些位置设置分界点,这样方案就能不重不漏。
即设 \(dp[n][0/1]\) 表示前 \(n\) 个分界点该分界点拆不拆开的方案数,那么
\[dp[n][0]=dp[n-1][0]+dp[n-1][1]\\dp[n][1]=dp[n-1][0]*\frac{b[n]-b[n-1]-1}{2}+dp[n-1][1]*\frac{b[n]-b[n-1]}{2}
\]
找到这种方案根据齐肯多夫定理一定存在这种方案,具体直接贪心从大到小选即可。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
typedef long long lll;
lll f[88],n,dp[88][2]; int g[88],tot;
lll iut(){
lll ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int main(){
f[1]=1,f[2]=2;
for (int i=3;i<88;++i) f[i]=f[i-1]+f[i-2];
for (int T=iut();T;--T){
n=iut(),tot=0;
for (int i=87;i;--i)
if (n>=f[i]) n-=f[i],g[++tot]=i;
reverse(g+1,g+1+tot);
dp[1][0]=1,dp[1][1]=(g[1]-1)>>1;
for (int i=2;i<=tot;++i)
dp[i][0]=dp[i-1][0]+dp[i-1][1],
dp[i][1]=dp[i-1][0]*((g[i]-g[i-1]-1)>>1)+dp[i-1][1]*((g[i]-g[i-1])>>1);
print(dp[tot][0]+dp[tot][1]),putchar(10);
}
return 0;
}