高精数论—— 数列(数论)

一道很诡异的题,但很有推理的必要。

 

数列(数论)

题目描述

有一个数列,满足两个性质:

1.     数列中任意两端相邻且长度相等的部分不完全相同,比如3 6 3 6 是不合法的。

2.     该数列是左右满足条件1的数列中字典序最小的。

3.     此为正数数列(原题中没说)

给出一个整数N,求数列的第N项。

输入

一个整数N

N<= 10^{1000}

输出

一个数,表示数列的第N项。

样例输入

20

样例输出

3

 题解

对于N<= 10^{1000} 的超大数据,我们用高精度数就可以了,但这也表明,再加上高精运算后,剩下的步骤必须降到此数的 log 级。

题目乍一看好像很难想,但当我们看到“字典序最小”时,就可以从1 开始推起了。

当 N = 1 时,数列为——  1

当 N = 2 时,数列就有可能出现重复了,得加上一个不为零的最小数。数列为——  1  2

当 N = 3 时,在上一个的基础上,只要不为 1 就行。数列为——  1  2  1

。。。。。。

最终数列为: 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 ......

我们可以发现,这个数列很有规律,(而且没理由认为它会打破规律)。

即当 N = 2^{x} * (2n+1)(乘一个任意奇数2n+1,n为任意非负整数)时,A[N] = x + 1 。

把N,也就是这个式子可以一直除以 2 ,最后当除到 x 次时会出现这个式子:2n + 1,此时判断N的个位会发现其模 2 等于一(小学知识)。

记录N /= 2 的次数,此数 + 1就是最终的答案,不难发现,这是 log 级的。

#include<cstdio>
#include<iostream>
#include<cstring>
#define max(x,y) ((x) > (y) ? (x) : (y))
#define min(x,y) ((x) < (y) ? (x) : (y))
#define LL long long
using namespace std;
int read() {
    int f = 1,x = 0;char s = getchar();
    while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
    while(s >='0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
    return x * f;
}
struct bi{
    int s[1005],len;
    bi(){len = 1;memset(s,0,sizeof(s));}
    bi(int on) {len = 1;memset(s,0,sizeof(s));s[1] = on % 10;}
    void read() {
        char ss = getchar();len = 0;
        while(ss < '0' || ss > '9') {ss = getchar();}
        while(ss >='0' && ss <= '9'){s[++len] = ss - '0';ss = getchar();}
        for(int i = 1;i <= (len >> 1);i ++)swap(s[i],s[len - i + 1]);
    }
}n,j(1);
LL c;
bi operator / (bi x,int y) {
    bi z;
    int m = 0;
    for(int i = x.len;i > 0;i --) {
        z.s[i] = x.s[i] + m * 10;
        m = z.s[i] % y;
        z.s[i] /= y;
        if(z.s[i]) z.len = max(z.len,i);
    }
    return z;
}
bool f;
int main() {
    n.read();
    while(n.len > 1 || n.s[1]) {
        f = n.s[1] & 1;
        n = n / 2;
        if(f) break;
        c ++;
    }
    printf("%lld\n",c);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值