Título: La maravillosa secuencia de
Gugudong Título:
Entrada:
Salida:
Muestra:
Ideas para resolver problemas: este problema sigue siendo muy difícil, principalmente porque los datos son demasiado grandes, si usa el prefijo y solo puede pasar los primeros seis puntos, 1e18 no es una broma y el número no se puede reunir; aquí está mi idea: primero , Primero creo una matriz de tamaño 8, almacenando el número de 1-10 ^ I: por
ejemplo, el primer elemento de la matriz es
112123123412345 ... 123456789 el tamaño es 45 y el
segundo elemento de la matriz es
112123 ... 123 ... 9123 ... 10123 ... 11 ... 123 ... 99 a 99, el
tercer elemento a 999,
hasta el octavo elemento (porque el noveno elemento ya es mayor que 1e18, así que hasta el octavo elemento)
, resto k menos que k El elemento más grande; en
este momento, el resto de k es 123 ... (10 ^ I) 123 .... (10 ^ i + 1) ... el último elemento de cada grupo (es decir, 123 ... x, después de x es 1) Lo mismo; después de eso, k se usa para restar continuamente el número de elementos en cada grupo hasta que k sea menor que el número de elementos en ese grupo, pero debe tenerse en cuenta aquí que si k es demasiado grande, se agotará el tiempo; así que usé el método de dicotomía aquí Optimicé el tiempo de esta elección; el resto es un grupo de 123 ... x, y el k es uno de ellos Bien, aquí utilizo el método recursivo, primero comparo k y 9, y lo comparo con mayor que 9 y luego 180 (10, 11, ... 99 en total 180 bits), y luego continúo comparando. . . Hasta que sea menor o igual que, y luego el número de elementos restantes sea el mismo (el primer elemento debe ser 10 a la potencia de i), usted sabe k, solo pregunte;
Código:
#include<iostream>
#include<cmath>
using namespace std;
long long t[17]={0};
long long h[17]={0};
long long t1[17]={0};
void solve()
{
h[0]=1;
for(int i=1;i<=18;i++)
{
h[i]=h[i-1]*10;
}
t[0]=0;
t1[0]=0;
for(int i=1;i<=16;i++)//t1[i]存的是从1-10^i-1的元素的个数
{
t1[i]=t1[i-1]+i*(h[i]-h[i-1]);
}
for(int i=1;i<=8;i++)//t[i]存的就是从组1到组123...10^1-1的元素的个数
{
t[i]=t[i-1]+(h[i]-h[i-1])*t1[i-1]+i*(h[i]-h[i-1])*(h[i]-h[i-1]+1)/2;
}
}
long long sol1(long long k,int num)
{
long long t=(h[num]-h[num-1])*num;
if(k<=t)//小于等于的情况,这时剩下的元素的位数相同,且第一个元素和k已经知道
{
long long k1=(k-1)/num;//这里就是求第k的数字
long long k2=k%num;
long long n=h[num-1]+k1;
if(k2==0)
{
n=n%10;
return n;
}else
{
long long u=n;
int total=0;
while(u>0)
{
u=u/10;
total++;
}
total=total-k2;
for(int i=0;i<total;i++)
{
n=n/10;
}
n=n%10;
return n;
}
}else//大于前去递归
{
k=k-t;
return sol1(k,num+1);
}
}
long long sol(long long k)
{
long long p;
for(int i=8;i>=0;i--)
{
if(t[i]<=k)
{
k=k-t[i];
p=i;
break;
}
}
if(k==0){return 9;}//减去那个最大的,如果为0直接返回9就行
long long p1=t1[p];//这个是减去的那个从1-10^i-1的元素的个数
p++;
while(1)
{
p1+=p;//这个是1-10^i的元素的个数
long long l=0,r=1000000000;
while(l+1<r)//二分
{
long long mid=(l+r)/2;
long long tt=mid*p1+p*(mid-1)*mid/2;
if(k>tt)
{
l=mid;
}else
{
r=mid;
}
}
k=k-(l*p1+p*(l-1)*l/2);//减去,之后剩下的就是123....x
k=sol1(k,1);//判断
return k;
}
}
int main()
{
solve();
int q;
cin>>q;
while(q--)
{
long long k;
cin>>k;
long long h1=sol(k);
cout<<h1<<endl;
}
}