二分水题 放组合数学里。。。可能有什么正规姿势吧Orz
112123123412345...这种串 分成长度1 2 3 4 5...的串 注意有多位数
把长度累加到一个数组里 注意要累加 因为查询的时候查的是原串中对应位置的数 因此要累加上前一次的长度 然后二分处该串前的总长 用查询的位置-之前串的总长 就是在最长的串中的位置 因此还要打个最长串的表
这些我都写一个循环里了 看着有点乱 可以拆开写。。。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define ll long long
#define INF 2147483648
using namespace std;
//2147483647
ll r[33333]; //二分查的数组
char str[233333]; //最长串的表
int tp,len; //累计二分数组长度 和最长串长度
void Init()
{
int i,j,cnt,pw,k,s;
r[0] = 0;
len = 1; //最长串从1开始 便于查询
for(tp = 1, i = 1, j = 1, cnt = 1, pw = 10; r[tp-1] <= 2147483647; i += cnt, tp++) //i累计当前串长 cnt累计最后一个数长度 j累计最后一个数(多位数) pw最后一个数位(1 10 100 100...)
{
r[tp] = r[tp-1] + i;
k = j;
s = pw/10;
while(s)
{
str[len++] = k/s + '0';
k%=s;
s /= 10;
}
++j;
if(j/pw)
{
pw *= 10;
cnt++;
}
}
tp--;
r[tp] = INF;
}
int main()
{
int l,rr,ans,t,mid;
ll pos;
Init();
scanf("%d",&t);
while(t--)
{
scanf("%lld",&pos);
l = ans = 0, rr = tp;
while(l <= rr) //二分查找
{
mid = l+rr>>1;
if(r[mid] < pos)
{
ans = mid;//小于查询位置的数中最大的 注意不可等
l = mid+1;
}else rr = mid-1;
}
printf("%c\n",str[pos-r[ans]]);
}
return 0;
}