#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;
}
posted @ 2021-12-10 19:37  lemondinosaur  阅读(33)  评论(0编辑  收藏  举报