寒假练习 1009 Number Sequence

   题意:给定序列a1a2a3...  定义ai代表1234...i,现在给定位置n,求解出这个位置的数字是多少。

   一开始想法简单,妄图利用几个计算就可以判断,

   但是后来发现问题,对于序列a12:123456789101112,它是有15位数的,所以不能简单的通过等差数列求和来解决,因为数据量比较大,所以普通方法会超时

   那么怎么办呢?这里利用到一个知识, 确定i的位数的方法,i的位数为log10(i)+1

   这样,就可以利用动态规划的思想来解决这个题目 

   len[i]代表1.....i这个子段的长度

   sum[i]代表a1a2a3...ai序列的长度

   状态转移方程:   len[i] = len[i-1] + log10(i) + 1;

                              sum[i] = sum[i-1] + len[i];

   一开始初始化预处理一下,就相当于一个离线算法,然后就可以解决了

   其实还有一种更快的想法就是一开始并不用预处理所有的情况,制定一个类似hash的东西,如果没有求出这一项的len[]和sum[],那么在再求解

   如果已经有的话就不用求解了,这便实现了动态的离线算法。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define maxn 31270

unsigned int len[maxn];  //len[i]代表1.....i这个子段的长度 
unsigned int sum[maxn];  //sum[i]代表a1a2a3...ai序列的长度 
unsigned int n;
void init() //初始化一次就可以使用,离线算法 
{
    len[1] = 1;
    sum[1] = 1;
    //状态转移方程
    //len[i] = len[i-1] + log10(i) + 1;
    //sum[i] = sum[i-1] + len[i];
    for(int i=2;i<maxn;i++)
    {//在序列中,log10(1)+1 求出的是i的位数
        len[i] = len[i-1] + (unsigned int) log10((double)i) + 1; 
        sum[i] = sum[i-1] + len[i];
    }
}
int main()
{
    int Tcas;
    scanf("%d",&Tcas);
    init();
    
    while(Tcas--)
    {
        scanf("%d",&n);
        int length = 0,i;
        
        for(i=1;sum[i]<n;i++) ;
        int pos = n - sum[i-1];
        
        i = 1;
        while(length < pos)  
        {  
            length += (int)log10((double)i) + 1;  
            i++;  
        }  
              
        int ans = ((i - 1) / (int)pow((double)10, length - pos)) % 10;  
        printf("%d\n", ans);  
    }
    
    system("pause");
    return 0; 
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值