cf1216E2 Numerical Sequence (hard version)

27 篇文章 0 订阅

记录一下心得

总之这道题的一些细节有点恶心我。

大概思路

依据出现数的位数分层,第一层9个,第二层90,一次类推
差不多是这样子:
1
12
123

————
12345678910
1234567891011

这样分,然后这对于每一程的位数都是有规律的,成等差数列,我们可以依据每层出现字符个数把该k为出现在哪一层找到,然后k-减去之前层的字符数,现在在找到具体的行,通过等差数列前n项和公式二分找到当前行数,然后减去前i-1行的字符数,在继续在当前行中找第k个字符。。。。依次下去。

代码

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
template<typename T>T quick_add(T a,T b,T mod){T ans = 0;while(b){if(b&1)ans = (ans+a)%mod;a = (a+a)%mod;b /= 2;};return ans%mod;}
template<typename T>T quick_mod(T a,T b,T mod){T ans = 1;while(b){if(b&1)ans = ans*a%mod;a = a*a%mod;b /= 2;};return ans%mod;}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
typedef unsigned long long ll;
#define int unsigned long long
const ll mod = 1e9+7;
ll ceng[15],sh[15];
 
inline void init(){
    ll shouxian = 0,gongbi = 1,num2 = 9,tp = 0;
    for(int i = 1;i <= 11;i++){
        shouxian = shouxian + num2/10*(i-1);
        sh[i] = shouxian;
        ceng[i] = (shouxian + i + shouxian + num2*i)*num2/2;
        ceng[i] += tp;
        //printf("shouxian:%lld num:%lld ceng:%lld\n",shouxian,num2,ceng[i]);
        tp = ceng[i];
        num2 *= 10;
    }
}
template<typename T>T quick_mod1(T a,T b){T ans = 1;while(b){if(b&1)ans = ans*a;a = a*a;b /= 2;};return ans;}
 
 
 main() {
    #ifndef ONLINE_JUDGE
       // freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    init();
    int q;cin >> q;
    while(q--){
        ll k;cin >> k;
        int id = lower_bound(ceng+1,ceng+12,k)-(ceng+1)+1;
        ll shouxian = sh[id];
        if(ceng[id-1]==k)id--;
        k -= ceng[id-1];
        ll l = 1,r = 9*quick_mod1(10ull,id-1);
        ll ans = 0;
        while(l<=r){
            ll mid = l+r>>1;
            ll tp = (shouxian + id + shouxian + id*mid)*mid/2;
            if(tp<=k){
                ans = mid;
                l = mid + 1;
            }else r = mid - 1;
        }   
        if(k==(shouxian + id + shouxian + id*ans)*ans/2)ans--;
        k -= (shouxian + id + shouxian + id*ans)*ans/2;
        ll num = 9;ans = 1;
        for(int i = 1;;i++){
            ll tp = 1ll*i*9*quick_mod1(10ull,1ull*(i-1));
            if(k>tp){
                k -= tp;
                ans = i+1;
            }else break;
        }
        ll tp1 = k/ans;
        ll tp2 = k%ans;
        ll i = quick_mod1(10ull,ans-1);
        char res;
        if(!tp2){
            i += tp1-1;
            char res = (i%10) + '0';
            cout << res << endl;
        }else {
            i += tp1;
            tp1 = i;
            int j = 0;
            char s[20];
            while(tp1){
                s[j] = (tp1%10)+'0';
                tp1 /= 10;
                j++;
            }
            for(int i = 1;i <= tp2;i++){
                res = s[--j];
            }
            cout << res << endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值