1 条题解

  • 0
    @ 2025-7-13 18:52:27

    🧠 题解思路

    这道题目看似简单,其实考察的是:

    如何在一个动态构造的无限数列中定位一个数字

    如何高效处理范围非常大的 ii(上限 2×1092 \times 10^9

    📈 序列构造逻辑

    记:

    kk 段子串为:Sk=123kS_k = 123\ldots k(长度不等于 kk,因为数字有多位)

    整体数列:S=S1+S2+S3++SkS = S_1 + S_2 + S_3 + \ldots + S_k

    所以我们要找的是:第 ii 个字符属于哪个 SkS_k,再定位它在 SkS_k 内是哪一个数的哪一位。

    ✅ 步骤详解

    第一步:找出目标字符位于哪个 SkS_k 中 我们需要累加每个 SkS_k 的长度直到超过第 ii 位。

    关键是:SkS_k 的长度不是 kk,而是长度为 11kk 所有整数拼接起来的长度。

    子串 SkS_k 的长度怎么求? 我们从 11 累加到 kk,每个数 nn 的位数是 len(n)\text{len}(n),所以:

    len ( 𝑆 𝑘 )

    ∑ 𝑛

    1 𝑘 digits ( 𝑛 ) len(S k ​ )= n=1 ∑ k ​ digits(n) 例如:

    S3=1+2+3S_3 = 1 + 2 + 3 → 字符串为 123,长度 3

    $S_10 = 12345678910` → 长度 11

    因此,我们可以从 k=1k=1 开始,不断累加 SkS_k 的长度,直到超过 ii 为止。

    这部分时间复杂度为 O(i)O(\sqrt{i}) 左右。

    第二步:确定位置 设目标落在 SkS_k 中:

    我们再遍历 1k1 \sim k,将 1k1 \sim k 的数字拼接起来,直到达到目标位置。

    将拼接好的字符串取出第 ii 位即可。

    代码实现

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<set>
    #include<cstdlib>
    #include<cstring>
    #include<stack>
    #include<string>
     
    using namespace std;
     
    #define N 31280
    #define s 31268
     
    int go[N];
    int num[N];
    int sum[N];
    int getnum(int k)
    {
    	int j=10;
    	int ans=1;
    	while ( k/j)
    	{
    		j*=10;
    		ans++;
    	}
    	return ans;
    }
     
    int main()
    {
    	int i,j,k;
    	go[0]=0;
    	for (i=1;i<N;i++)
    	{
    		go[i]=getnum(i);
    	}
    	num[0]=0;
    	for (i=1;i<N;i++)
    	{
    		num[i]=num[i-1]+go[i];
    	}
    	sum[0]=0;
    	for (i=1;i<N;i++)
    	{
    		sum[i]=sum[i-1]+num[i];
    	}
     
    	int n;
    	int cas;
    	cin>>cas;
    	while (cas--)
    	{
    		cin>>n;
    		for (i=s-1;i>=0;i--)
    		{
    			if ( n>sum[i])
    			{
    				n-=sum[i];
    				break;
    			}
    		}
    		//cout<<n<<' ';
    		
    		for (i=N-1;i>=0;i--)
    		{
    			if (n>num[i])
    			{
    				n-=num[i];
    				break;
    			}
    		}
    		//cout<<n<<' ';
    		i++;
    		k=1;
    		//cout<<i<<' ';
    		//cout<<go[i]<<' ';
    		n=go[i]-n+1;
    		while (--n)
    		{
    			i/=10;
    		}
    		cout<<i%10<<endl;
    	}
    }
    
    
    • 1

    信息

    ID
    20
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者