/**//* 题意:一个数可以写成Fibonacci数组成(整数的Fibonacci分解,是唯一的),即 N = anFn + an-1Fn-1 ++ a1F1 ai=0,1 (不会有相邻的1) 1 = 1 2 = 10 3 = 100 4 = 101 现将所有的自然数的Fibonacci表示写成一串:110100101100010011010 问前N个中1的个数 N <= 10^15 F[0] = 1,F[1] = 1,F[2] = 2,F[3] = 3,F[4] = 5
定义S[i]表示第i个Fibonacci之前的数的Fibonacci表示中1的个数之和 B[i]表示第i个Fibonacci之前的数的位数之和 递推式写一下几个数即可知道 先二分查找出 B[i-1] < N <= B[i] 然后得到最后的一个自然数是 (N-B[id-1])/id -1 + F[id]; 然后再统计下即可 */
#include <cstdio> #include <cstring> #include <algorithm>
using namespace std;
const int MAXN = 70;
long long S[MAXN],F[MAXN],B[MAXN]; int n;
void init() { S[1] = 1,F[0] = 1,B[1] = 1; F[1] = 1; for(int i=2;;i++) { S[i] = S[i-1] + S[i-2] + F[i-1]; F[i] = F[i-1] + F[i-2]; B[i] = B[i-1] + i*F[i-1]; if(B[i] >= 1000000000000000LL){n= i;break;} } } int find(long long N) { int low = 0,high = n; while(high-low>1) { int mid = (low + high )>>1; if(B[mid]>=N)high = mid; else low = mid; } return high; } long long solve(long long N,int id) { long long num = (N-B[id-1])/id -1 + F[id]; int r = (N-B[id-1])%id;
long long ans = 0, x= num+1; int i = id; while(num>0) { if(num>=F[i])//有点类似数位类统计的逐位确定 { ans += (num-F[i]+1)+S[i-1]; num-=F[i]; } i--; } i = id; while(r && x>0) { if(x>=F[i])ans++,x-=F[i]; r--; i--; } return ans; } int main() { #ifdef ONLINE_JUDGE #else freopen("in","r",stdin); #endif
init(); long long N; while(scanf("%lld",&N)!=EOF) { if(N == 0){puts("0");continue;} printf("%lld\n",solve(N,find(N))); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|