UVA10479 找规律+递归

UVA 10479 找规律+递归

记:想清楚了写,弄明白每个变量的含义,就会把很复杂的东西弄得一清二楚。

题意

Hendrie序列是个自描述序列

H(1)=0,如果把H中的每个整数x变成x个0

分析

找规律

0 1 0 2 1 0 0 3 0 2 1 1 0 0 0 4 1 0 0 3 0 2 0 2 1 1 1 0 0 0 0 5 0 2 1 1 0 0 0 4 1 0 0 3 1 0 0 3 0 2 0 2 0 2 1 1 1 1 0 0 0 0 0 6

  1. 2 k 2^k 2k 位是k

  2. 把序列在 2 k 2^k 2k 处分割,得到子串

    0 |1 |0 2 | 1 0 0 3| 0 2 1 1 0 0 0 4| 1 0 0 3 0 2 0 2
     1 1 1 0 0 0 0 5| 0 2 1 1 0 0 0 4 1 0 0 3 1 0 0 3 0 
     2 0 2 0 2 1 1 1 1 0 0 0 0 0 6
    

    所以可以得到子串 .子串的长度len=1<<(编号-1) (编号=0时不成立)

    s[0]=0,

    s[1]=1

    s[2]=02

    s[3]=1003

    s[4]=02110004

    s[5]=1 0 0 3 0 2 0 2 1 1 1 0 0 0 0 5

  3. 在第 2 k 2^{k} 2k 往前到 第 2 k − 1 2^{k-1} 2k1 处,为 k-1个s[0], k-2个s[1],…1个s[k-2].

    比如第 2 6 = 32 2^6=32 26=32 处, 0 2 1 1 0 0 0 4 1 0 0 3 1 0 0 3 0 2 0 2 0 2 1 1 1 1 0 0 0 0 0 6,就是5个"0",4个“1”,3个“02”,2个“1003”,1个“02110004”。

代码实现遇到问题
  1. <<最大只能左移30位,就会溢出

  2. 范围是0<n< 2 63 2^{63} 263 ,因此只能用unsigned long long

算法过程
  1. 给一个n,找到它属于的范围 ( 2 k − 1 , 2 k ) (2^{k-1},2^k) (2k1,2k)

  2. 如果 n = 2 k n=2^k n=2k ,那么就直接返回k,

  3. 否则用 2 k − n + 1 2^k-n+1 2kn+1 得到前缀的长度,再不断的减去(k-i-1)s[i]的长度,直到找到存在哪个s[i]中。比如44,44存在于 2 5 和 2 6 2^5和2^6 2526 之间,64-44=20,20-5*1=15, 15- 4*1=11, 11-3*2= 5, 5<24,于是 5%4=1,可以知道答案存在于s[3]的倒数第1位中,

    (如果此处得到的是0,那么答案应该存在于s[i]的倒数第(s[i]的长度)位。

  4. 再利用子串的分布情况,把求s[3]的第4位转化为求n, n = 2 3 − 1 + 1 = 8 n=2^3 -1+1=8 n=231+1=8 ,再跳转到第2步。

代码

#include "bits/stdc++.h"
using namespace  std;
typedef  unsigned long long ll ;
ll data[100];  //2^k
ll dfs(ll n)
{
    ll k=0;
    for(;;++k)if(data[k]>=n)break;

    if( data[k]==n)return k;

    //单独处理子串为0的情况,编号为0的子串长度为0
    ll cha=data[k]-n;
    if(cha<=(k-1))return 0;
    cha-=k-1;

    int subs;
    //子串编号为subs的长度为data[subs-1], 处在(data[subs-1],data[subs]]这个位置上。
    for( subs=1;;++subs)
    {
        if( (k-subs-1) <1 )break;

        if( cha<=(data[subs-1]*(k-subs-1) )){
            cha=cha% data[subs-1];
            if(cha==0) cha=data[subs-1];  //如果是0,那么答案应该存在于该子串的倒数第data[subs-1] 位。
            n=data[subs]-cha+1;
            return dfs(n);
        }
            else cha-=data[subs-1]*(k-subs-1);
    }

}
int main()
{
//    freopen("in.text","r",stdin);

    data[0]=1;
    for(int k=1;k<=63;++k) data[k] = data[k - 1] * 2;
    

    ll n;
	while (cin>>n&&n)cout<<dfs(n)<<endl;
  
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是Mally呀!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值