• codeforces 1216E1 Numerical Sequence (easy version) (前缀和/二分)


    题目链接:https://vjudge.net/problem/CodeForces-1216E1

      题目描述就是给你一串数,可以分成若干段,每段为这个数字以及这个数字前几个数就像1 12 123 1234 12345这样,然后给你一个数i

    让你求这个数列第ai位的数。

      首先我们先想对于1234567891011121314这列数来说,每个数字的末位处于这个数以及这个数前面所有数的位数之和,比如5就位于第

    5个位置,10的0位于第11个位置,14的4位于第19个位置,我们可以用一个前缀和来表示这些数的位置。

      然后对于112123123412345这列数来说, 第一个1出现的位置就是1第一个2的位置就是1的位数加上12的位数,第一个11末位1的位置

    就是1 + 12 + 123 + 1234 。。。的位数,即上面位数前缀和的前缀和。

      对于一个位置num来说,它前面必定有若干个1 12 123 1234这样的序列,所以我们就可以用二分在前缀和的前缀和序列中找一个小于他

    的最大的数,那么他们的差就是序列12345678910...列数中的某个位置,即在前缀和序列中的位置,这里我们可以再用一次二分,然后求得

    一个大于或者等于这个数的最小的值,那么num在减去这个位置就是答案了

      

    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<string>
    #include<vector>
    #include<climits>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define endl '\n'
    #define max(a, b) (a > b ? a : b)
    #define min(a, b) (a < b ? a : b)
    #define mst(a) memset(a, 0, sizeof(a))
    #define IOS ios::sync_with_stdio(false)
    #define _test printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> P;
    const double pi = acos(-1.0);
    const double eps = 1e-7;
    const ll MOD = 1e9+7;
    const int INF = 0x3f3f3f3f;
    const int _NAN = -0x3f3f3f3f;
    const int NIL = -1;
    const int maxn = 2e5+10;
    ll _ls[maxn], _sumls[maxn];
    int main(void) {
        for (ll i = 1; i<maxn; ++i) {
            ll t = (ll)((log10(i)+eps)+1); //求数字位数
            _ls[i] = _ls[i-1] + t; //求1234567位数的前缀和(1234567中每个数字末位对应的位数)
            _sumls[i] = _sumls[i-1] + _ls[i]; //求前缀和的前缀和(1121231234中每个数字第一次出现时其末位对应的位数)
        }
        //printf("%lld %lld\n", _ls[maxn-1],_sumls[maxn-1]);
        int n;
        scanf("%d", &n);
        while(n--) {
            ll num;
            scanf("%lld", &num);
            ll *pos1 = lower_bound(_sumls+1, _sumls+maxn, num); 
            if (*pos1 == num) 
                printf("%d\n", (pos1-_sumls)%10);//刚好对应某个第一次出现的数字的末尾
                //指针相减默认是int类型,如果用lld输出结果会出错
            else {
                //对应某个数字的某位上
                --pos1; 
                num -= *pos1;
                ll *pos2 = lower_bound(_ls+1, _ls+maxn, num);
                string nums; //把这个数字转成字符串
                ll t2 = pos2-_ls;
                while(t2) {
                    nums += t2%10 + '0';
                    t2 /= 10;
                }
                reverse(nums.begin(), nums.end());
                --pos2;
                num -= *pos2; //求出结果在字符串上的位置
                printf("%c\n", nums[num-1]);
                nums.clear();
            }
        }
        return 0;
    }
  • 相关阅读:
    nginx服务器安装及配置文件详解
    关于mysql字段时间类型timestamp默认值为当前时间问题
    怎样才能自学好Java?
    别再问我做一个网站多少钱了!
    2016年里做前端是怎样一种体验
    从网上找的 visual studio 的各个版本下载地址,vs2010/vs2012/vs2013带注册码
    强烈推荐:程序员接私活那点事
    夹缝中生存的个人开发者
    关于ODP.NET连接数监控及相应的windbg分析提示
    Oracle虚拟索引,大表或生产环境下预估索引效果的好东西
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/12288504.html
Copyright © 2020-2023  润新知