BZOJ2656 [Zjoi2012]数列

Description

小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式:

$$\begin{aligned}
A_0 &= 0\\
A_1 &= 1\\
A_{2i} &= A_i\\
A_{2i+1} &= A_i + A_{i+1}
\end{aligned}$$

小白作为一个数学爱好者,很快就计算出了这个数列的通项公式。于是,小白告诉小蓝自己已经做出来了,但为了防止小蓝抄作业,小白并不想把公式公布出来。于是小白为了向小蓝证明自己的确做出来了此题以达到其炫耀的目的,想出了一个绝妙的方法:即让小蓝说一个正整数N,小白则说出 的值,如果当N很大时小白仍能很快的说出正确答案,这就说明小白的确得到了公式。但这个方法有一个很大的漏洞:小蓝自己不会做,没法验证小白的答案是否正确。作为小蓝的好友,你能帮帮小蓝吗? 

Input

输入文件第一行有且只有一个正整数,表示测试数据的组数。

第2~T+1行,每行一个非负整数N

Output

输出文件共包含T行。

第i行应包含一个不含多余前缀0的数,它的值应等于An(n为输入数据中第i+1行被读入的整数)

Sample Input

3
1
3
10

Sample Output

1
2
3

题解

手算几组小数据可以发现(也可以证明)在展开k次之后一定会得到$$xA_{\lfloor n/2^k \rfloor}+yA_{\lfloor n/2^k \rfloor+1}$$的形式,并且若

$$A_n = uA_i + vA_{i+1}$$,那么:

若i是偶数,则

$$A_n = (u+v)A_{i/2} + vA_{i/2+1}$$

若i是奇数,则

$$A_n = uA_{i/2} + (u+v)A_{i/2+1}$$

高精搞一搞即可。

代码:

#include <algorithm>
#include <cstdio>
#include <cstring>
const int N = 105;
int A[N], B[N], C[N];
char s[105];
void div2() {
  for (int i = A[0]; i; --i) {
    if (i && (A[i] & 1)) A[i - 1] += 10;
    A[i] >>= 1;
  }
  while (A[0] && !A[A[0]]) --A[0];
}
void add(int *a, int *b) {
  int t = 0;
  for (int i = 1; i <= b[0] || t; ++i) {
    t = (a[i] += b[i] + t) / 10;
    a[i] %= 10;
  }
  a[0] = std::max(a[0], b[0]);
  while (a[a[0] + 1]) ++a[0];
}
int main() {
  int T;
  scanf("%d", &T);
  while (T--) {
    scanf("%s", s);
    if (!strcmp(s, "0")) {
      puts("0");
      continue;
    }
    A[0] = strlen(s);
    for (int i = 0; i < A[0]; ++i)
      A[A[0] - i] = s[i] - '0';
    memset(B, 0, sizeof B);
    memset(C, 0, sizeof C);
    B[0] = B[1] = 1;
    while (A[0]) {
      if (A[1] & 1) add(C, B);
      else add(B, C);
      div2();
    }
    for (int i = C[0]; i; --i)
      putchar(C[i] + '0');
    putchar('\n');
  }
  return 0;
}

  

转载于:https://www.cnblogs.com/y-clever/p/7373482.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值