埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 F- 1 + 2 = 3? (好难的找规律题)

斐波那契真的牛掰

题目链接

题目描述:

小Y在研究数字的时候,发现了一个神奇的等式方程 ,他屈指算了一下有很多正整数x满足这个等式,比如1和2,现在问题来了,他想知道从小到大第N个满足这个等式的正整数,请你用程序帮他计算一下。
(表示按位异或运算)

输入描述:

第一行是一个正整数 T<=100,表示查询次数。
接着有T行,每行有一个正整数N(N<=1e12),表示小Y的查询。
输出描述::
对于每一个查询N,输出第N个满足题中等式的正整数,并换行。
示例1

输入:

4
1
2
3
10

输出:

1
2
4
18

打表列出前100个数,找下规律

#include<bits/stdc++.h>
#define ll long long 
#define N 100005
int inf = 0x3f3f3f3f;
using namespace std;
string solve(int n){    //将十进制转换成二进制 
    string s;
    char c;
    while(n){
        c = '0' + n % 2;
        s = c + s;
        n /= 2;
    }
    return s;
}
int main (){ 
    int now=0;  
    printf("查询次数 答案 二进制形式\n"); 
    for(int i=1;;i++){
        if(((i ^ (2 * i)) == 3 * i)){
            string s;
            int n;
            s = solve(i);
            printf("%4d%6d       ",++now,i);
            cout << s << endl;
        }       
        if(now == 100)
            break;
    }   
    return 0;  
}  
查询次数 答案 二进制形式
   1     1       1          //二进制1位的有1个 
   2     2       10         //二进制2位的有1个 
   3     4       100     
   4     5       101        //二进制3位的有2个
   5     8       1000
   6     9       1001
   7    10       1010       //二进制4位的有3个
   8    16       10000
   9    17       10001
  10    18       10010
  11    20       10100
  12    21       10101      //二进制5位的有5个
  13    32       100000     
  14    33       100001
  15    34       100010
  16    36       100100
  17    37       100101
  18    40       101000
  19    41       101001
  20    42       101010     //二进制6位的有8个
  21    64       1000000    
  22    65       1000001
  23    66       1000010
  24    68       1000100
  25    69       1000101
  26    72       1001000
  27    73       1001001
  28    74       1001010
  29    80       1010000
  30    81       1010001
  31    82       1010010
  32    84       1010100
  33    85       1010101    //二进制7位的有13个
  34   128       10000000
  35   129       10000001
  36   130       10000010
  37   132       10000100
  38   133       10000101
  39   136       10001000
  40   137       10001001
  41   138       10001010
  42   144       10010000
  43   145       10010001
  44   146       10010010
  45   148       10010100
  46   149       10010101
  47   160       10100000
  48   161       10100001
  49   162       10100010
  50   164       10100100
  51   165       10100101
  52   168       10101000
  53   169       10101001
  54   170       10101010
  55   256       100000000
  56   257       100000001
  57   258       100000010
  58   260       100000100
  59   261       100000101
  60   264       100001000
  61   265       100001001
  62   266       100001010
  63   272       100010000
  64   273       100010001
  65   274       100010010
  66   276       100010100
  67   277       100010101
  68   288       100100000
  69   289       100100001
  70   290       100100010
  71   292       100100100
  72   293       100100101
  73   296       100101000
  74   297       100101001
  75   298       100101010
  76   320       101000000
  77   321       101000001
  78   322       101000010
  79   324       101000100
  80   325       101000101
  81   328       101001000
  82   329       101001001
  83   330       101001010
  84   336       101010000
  85   337       101010001
  86   338       101010010
  87   340       101010100
  88   341       101010101
  89   512       1000000000
  90   513       1000000001
  91   514       1000000010
  92   516       1000000100
  93   517       1000000101
  94   520       1000001000
  95   521       1000001001
  96   522       1000001010
  97   528       1000010000
  98   529       1000010001
  99   530       1000010010
 100   532       1000010100

找规律:

  1. 答案对应的二进制的位数符合斐波那契数,(打表斐波那契)
  2. N和斐波那契的有关,给定一个N可以判断,此时答案的二进制位数。(打表斐波那契的和)
  3. 举一个例子:当N等于70,答案的二进制为:100100010,根据打表的斐波那契的和,可以判断答案的二进制是9位(55对应1000000000),余下的100010,刚好是N-55的二进制。递推!

代码实现:

#include<bits/stdc++.h>
#define ll long long 
#define N 100005
int inf = 0x3f3f3f3f;
ll f[N],sum[N],ans[N];
using namespace std;
int main (){ 
    f[1] = f[2] = 1;
    sum[1] = 1; 
    sum[2] = 2;
    for(int i = 3; i <= 60; i++){   //打表斐波那契、斐波那契的和 
        f[i] = f[i-1] + f[i-2];
        sum[i] = sum[i-1] + f[i]; 
    }
    int t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        ll ans=0;
        while(n){
            for(int i = 1; i <= 60; i ++){
                if(n <= sum[i] && n > sum[i-1]){    //找到n对应答案的二进制位数 
                    ans += 1LL << i-1;
                    n -= sum[i-1] + 1LL;
                    //ans += (ll) pow(2, i-1LL);//pow前面要加longlong要不然会爆数据                
                    break;
                }
            }       
        }
        cout<<ans<<endl;        
    }
    return 0;  
}  
阅读更多
文章标签: 斐波那契数的应用
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭