zoukankan      html  css  js  c++  java
  • Atcoder rc122-c Calculator 斐波那契

    image

    传送门


    题解


    先说结论: 任意正整数可以拆分成若干个斐波那契数

    斐波那契数列: 1 1 2 3 5 8 13 21 34
    例 17 = 13 + 3 + 1
    看上去是对的,怎么证明呢?
    首先假如每一个斐波那契数可以重复多次,那么显然成立(因为可以重复使用(1)来构成)
    进一步 因为(f_{x} = f_{x-1} + f_{x-2})(f_{x-1} > f_{x-2}) 所以 (f_{x} < 2f_{x-1})
    假设我们使用了两次(f_{x-1}), 那么我们可以使用一次类似进位的操作把他进成(f_{x})(剩下的递归构造)
    这样一旦有重复的我们就进位,最后可以得到一个不重复的子数列

    也就是说 任意正整数可以拆分成若干个斐波那契数的和
    (我把这玩意称作斐波那契进制数?

    好了,回到我们这道题目上来, 不难发现反复进行3,4操作实际上就是在计算斐波那契数列
    那么问题来了我们可以通过这个方式来得到一个斐波那契数,但是怎么才能得到若干个斐波那契数的和呢
    来看看,我们让第三个斐波那契数加1(其实就是在计算过程中使用1, 2操作

    1 2 3 4 5 6 7 8 9 10
    1 1 2 3 5 8 13 21 34 55
    1 1 3 4 7 11 18 29 47 76
    +0 +0 +1 +2 +3 +5 +8 +13 +21 +34
    容易发现我们在第三项加一,后面增加的数又构成了斐波那契数列。
    对, 就是你想的那样, 我们想要让x最终变成76 (55 + 34)的话, 就直接在第三项计算完之后调用操作1/2,让他加一,这样在计算到55时,就会加34, 也就是 55 + 34 = 76;

    好了,剩下的就只有推式子和实现了。

    void pre(){
    	f[0]=0, f[1]=1;
    	for(int i=2; i<=100; i++) f[i] = f[i-1] + f[i-2];
    }
    
    int main(){
    	a=read();
    	pre();
    	
    	n=100;
    	while(f[n] > a) n--;
    	
    	for(int i=n; i>0; i--){
    		if(a>=f[i]){
    			v[n-i+1] = 1;
    			a -= f[i];
    		}
    	}
    	
    	int ans = 0;
    	cout << 130 << endl;
    	
    	int it = (n%2);
    	for(int i=1; i<=n; i++){
    		
    		if(i != 1){
    			ans++;
    			cout << it?3:4 << endl; 
    		}
    		
    		if(v[i]){
    			ans++;
    			cout << it?1:2 << endl;
    		}
    		it = !it;
    	}
    	
    	for(int i=ans; i<130; i++) cout << 4 << endl;
    	return 0;
    } 
    
  • 相关阅读:
    4.JDBC编程
    android 多线程
    android 网络请求Ⅰ
    android 数据存储Ⅱ
    android 数据存储Ⅰ
    android 界面设计基本知识Ⅳ
    《将博客搬至CSDN》
    android 界面设计基本知识Ⅲ
    android 界面设计基本知识Ⅱ
    android 界面设计基本知识
  • 原文地址:https://www.cnblogs.com/ltdjcoder/p/14880243.html
Copyright © 2011-2022 走看看