[CF126D]Fibonacci Sums/[BJOI2012]最多的方案
[CF126D]Fibonacci Sums/[BJOI2012]最多的方案
题目大意:
将\(n(n\le10^9)\)表示成若干个不同斐波那契数之和的形式,求方案数。
思路:
如果不考虑\(0\),则\(10^9\)以内的斐波那契数只有86个。
首先求出字典序最大的方案,考虑分裂里面的数。
用\(c_i\)表示字典序最大方案在斐波那契数列中的下标(递增),\(f_{i,j}\)表示考虑到第\(i\)个数,本身是否分裂的方案数。
转移方程为:
\[f_{i,0}=f_{i-1,0}+f_{i-1,1}\\
f_{i,1}=\lfloor\frac{c_i-c_{i-1}-1}2\rfloor f_{i-1,0}+\lfloor\frac{c_i-c_{i-1}}2\rfloor f_{i-1,1}
\]
单次询问时间复杂度\(\mathcal O(86)\)。
源代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
typedef long long int64;
inline int64 getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int64 x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
int64 f[87][2],c[87],fib[87]={
0,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,1771\
1,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5\
702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296\
,433494437,701408733,1134903170,1836311903,2971215073ll,4807526976ll,7778742049l\
l,12586269025ll,20365011074ll,32951280099ll,53316291173ll,86267571272ll,13958386\
2445ll,225851433717ll,365435296162ll,591286729879ll,956722026041ll,1548008755920\
ll,2504730781961ll,4052739537881ll,6557470319842ll,10610209857723ll,171676801775\
65ll,27777890035288ll,44945570212853ll,72723460248141ll,117669030460994ll,190392\
490709135ll,308061521170129ll,498454011879264ll,806515533049393ll,13049695449286\
57ll,2111485077978050ll,3416454622906707ll,5527939700884757ll,8944394323791464ll\
,14472334024676221ll,23416728348467685ll,37889062373143906ll,61305790721611591ll\
,99194853094755497ll,160500643816367088ll,259695496911122585ll,42019614072748967\
3ll,679891637638612258ll
};
int main() {
for(register int T=getint();T;T--) {
int64 n=getint();
int cnt=0;
for(register int p=std::lower_bound(&fib[1],&fib[87],n)-fib;p;p--) {
if(n>=fib[p]) {
n-=fib[p];
c[++cnt]=p;
}
}
std::reverse(&c[1],&c[cnt]+1);
f[1][0]=1;
f[1][1]=(c[1]-1)/2;
for(register int i=2;i<=cnt;i++) {
f[i][0]=f[i-1][0]+f[i-1][1];
f[i][1]=f[i-1][0]*((c[i]-c[i-1]-1)/2)+f[i-1][1]*((c[i]-c[i-1])/2);
}
printf("%lld\n",f[cnt][0]+f[cnt][1]);
}
return 0;
}