Kolakoski序列

定义

Kolakoski序列是一个仅由1和2组成的无限数列,是一种通过“自描述”来定义的数列。他的前几项为
1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1,2,2,1,2,1,1,2,1,2,2,1,1,…(OEIS上的A000002)
它的定义很简单,若把数列中相同的数定为一组,令a(1)=1,a(2)=2,则a(n)等于第n组数的长度。
可以根据这个定义来推算第三项以后的数:例如由于a(2)=2,因此第2组数的长度是2,因此a(3)=2,;
由于a(3)=2,所以第三组数的长度是2,因此a(4)=a(5)=1;由于a(4)=1,a(5)=1,所以第四组数和第五组数的长度都为1,因此a(6)=2,a(7)=1,以此类推。

说明

上面的构造方法或者说是定义首先要牢牢记住 a(n) 不仅代表第n位的值,还代表第n组的数字个数
比如现在由序列(1, 2)生成Kolakoski序列。
已知a(1) = 1,所以第一组只有一个数,并且这个数已经是1了,那么下一组的数值应该去找序列的下一位,也就是2。
因此a(2) = 2,它又代表了第二组有两个数字,又根据a(2) = 2, 能够得到a(3) = 2。
又因a(3) = 2,它代表第三组有两个数字,上一组值是2,所以这一组值应该是1,所以a(4) = 1 a(5) = 1
又因a(4) = 1,代表第四组有一个数字,上一组使用的是1,所以这一组为2,因此a(6)=2
因a(5) = 1, 代表的是第五组有一个数字,上一组使用的是2,因此a(7) = 1

这里需要记住a(n)还代表第n组的数字个数。

这个序列有什么神奇的呢?对于(1,2)构造的序列,
1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1,2,2,1,2,1,1,2,1,2,2,1,1…
我们把相同数字进行合并得到
[1], [2,2], [1, 1], [2], [1], [2,2], [1], [2, 2], [1], [2, 2], [1,1]…

我们看每一组的数字个数,得到这样一个序列
1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 2…
不难看出它还是一个Kolakoski序列。

推广

那么有了Kolakoski的构造方法后,能不能举一反三,将其他序列也构造成Kolakoski序列呢?
当然可以了,比如序列(2, 1, 3, 1) 构造成Kolakoski序列是什么样呢?
已知a(1) = 2,因此a(1) = 2, a(2) = 2。
由上面知道了a(2) = 2,因此第二组有两个数字,而第一组使用了1,所以这一组用第二位的1. 既 a(3) = 1, a(4) = 1
a(3) = 1,所以a(5) = 3
a(4) = 1, 因此a(6) = 1
a(5) = 3, 因此a(7) = a(8) = a(9) = 2
… …
最后得到序列
[2, 2, 1, 1, 3, 1, 2, 2, 2, 1, 3, 3, 1, 1, 2, 2, 1, 3, 3, 3, 1, 1, 1, 2, 1, 3, 3, 1, 1,…]

例题

题目地址

hdu6130

题意

就是问你由(1,2)构造的Kolakoski序列中第n位值。

解题思路

预处理出题目范围的Kolakoski,然后直接输出即可。

AC代码

#include <iostream>

using namespace std;

int maxnum = 10000004;
int num[10000005];

void init()
{
    num[1] = 1;
    num[2] = 2;
    num[3] = 2; 
    
    int t = 3;  //t代表组num[t] 就是这一组有多少个数字 
    
    for (int i=4; i<=maxnum; i++)
    {
        int temp = num[t++];
        
        if (temp == 2)
        {
            if (num[i-1] == 1)
            {
                num[i] = 2;
                num[i+1] = 2;
                i++;
            }
            else
            {
                num[i] = num[i+1] = 1;
                i++;
            }
        }
        else
        {
            if (num[i-1] == 1)
                num[i] = 2;
            else
                num[i] = 1;
        }
    }
}

int main()
{
    init();
    
    int t, n;
    
    cin >> t;
    
    while (t--)
    {
        cin >> n;
        
        cout << num[n] << endl;
    } 
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值