题目链接:http://codeforces.com/contest/126/problem/D
题意:一个数能够有多种由互不同样的斐波那契数组成的情况;
解法:dp,easy证明:每一个数通过贪心能够找到一种最少数量的斐波那契数组成方案。然后找到有多少种取代的方案;dp[i][0]表示前i个里面第i个数不动的方案数。dp[i][1]表示前i个里面第i个数下放的方案数。由于下放最多下放到已经有了的数,并且下放过程中,i下放。那么i-1就会固定无法下放,最多仅仅能继续下放i-2。直到下放到已经存在的数位置。
转移方程见代码:
代码:
/****************************************************** * @author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> //freopen ("in.txt" , "r" , stdin); using namespace std; #define eps 1e-8 #define zero(_) (abs(_)<=eps) const double pi=acos(-1.0); typedef long long LL; const int Max=100010; const int INF=1e9+7; LL fi[120]; int tool[100]; int p=0; LL dp[100][2]; int main() { fi[1]=1; fi[2]=2; for(int i=3; i<=90; i++) fi[i]=fi[i-1]+fi[i-2]; // cout<<fi[90]<<endl; int t=0; LL a; scanf("%d",&t); while(t--) { p=0; cin>>a; int x=90; while(a) { if(fi[x]<=a) { tool[p++]=x; a-=fi[x]; } //cout<<a<<" "<<x<<endl; x--; } reverse(tool,tool+p); dp[0][0]=1; dp[0][1]=(tool[0]-1)/2; for(int i=1;i<p;i++) { dp[i][0]=dp[i-1][0]+dp[i-1][1]; dp[i][1]=(tool[i]-tool[i-1]-1)/2*dp[i-1][0]+ (tool[i]-tool[i-1])/2*dp[i-1][1]; } cout<<dp[p-1][0]+dp[p-1][1]<<endl; } return 0; }