1626: 又是A+B吗?(二分)

 

题目描述

其实这个题本来应该是那道撼烁古今的A+B签到题,但LCC小王子一看不乐意了,说:“这么经典的题怎么能让别人做,我们要留着自己做,马上把这道题给我换了。”于是把原本经典的A+B签到题改成了现在这道题。哎。。。啥都不说了,你们还是自己看题吧。

给你一个正整数n,找出位于序列组S1S2S3...Sk中第n个位置的数字。序列Sk就是一个从1到k的正整数序列。例如,一个80位的序列组为:11212312341234512345612345671234567812345678912345678910123456789101112345678910

输入

多实例测试。每行输入一个整数n(1<=n<=2147483647)

输出

每个测试实例输出一个整数,占一行,表示序列组第n个位置上的数字。

样例输入

8
3

样例输出

2
2

两次预处理,预处理 两个数组: 

a[N] , b[N] 。 b[i]:1,2,3, .. i 的长度;  a[i] : S1S2S3...Sk    k = i 时字符串的长度。

两次二分: 

第一次 二分 从 a[N] 中找到  长度 小于等于 n 最大的 i , 如果 a[i] == n, 输出 i%10 结束,a[i] != n 进行下一步 。

第二次二分 从 b[N] 中找到 长度 小于等于 n-a[i] 最大的 j,  如果 b[j] == n-a[i], 输出 j%10 结束,b[j] != n-a[i] 进行下一步 。

输出 j+1 这个数字 的 n-a[i]-b[j] 位。

#include <iostream>
#include <cmath>
using namespace std;

long long  a[1000100];
long long b[1000100];

long long find1(int left, int right, long long e)
{
    int mid;
    while(left <  right)
    {
        mid = (left+right)/2;
        (e < a[mid]) ? right = mid : left = mid + 1;
    }
    return --left;
}
long long find2(int left, int right, long long e)
{
    int mid;
    while(left <  right)
    {
        mid = (left+right)/2;
        (e < b[mid]) ? right = mid : left = mid + 1;
    }
    return --left;
}

int main()
{
    a[0] = 0;
    b[0] = 0;
    for(int i=1; i<=9; i++)
    {
        b[i] = i;
        a[i] = a[i-1] + b[i];
    }
//	for(int i=1; i<=9; i++)
//	 cout << a[i] << endl;

    for(int i=10; i<=99; i++)
    {
        b[i] = b[i-1] + 2;
        a[i] = a[i-1] + b[i];
    }
    for(int i=100; i<=999; i++)
    {
        b[i] = b[i-1]+3;
        a[i] = a[i-1] + b[i];
    }
    for(int i=1000; i<=9999; i++)
    {
        b[i] =b[i-1]+4;
        a[i] = a[i-1] + b[i];
    }
    for(int i=10000; i<=99999; i++)
    {
        b[i] = b[i-1]+5;
        a[i] = a[i-1] + b[i];
    }

    long long n;
    while(cin >> n)
    {
// for(int i=a[999]; i<=a[1000]; i++) {
        //      n = i;
        int cnt;
        cnt = find1(0, 99998, n);
        n -= a[cnt];
        //cout << cnt << " " << n << endl;
        if(n == 0)
        {
            cout << cnt%10 << endl;
            continue;
        }

        cnt = find2(0, 99998, n);
        //	cout << n << " " << cnt << endl;

        n -= b[cnt];
        if(n == 0)
        {
            cout << cnt%10 << endl; // " ";
            continue;
        }

        //	cout << n << " " << cnt << endl;
        cnt ++;
        while(cnt >= pow(10, n))
        {
            cnt /= 10;
        }
        cout << cnt%10 << endl; // " ";
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值