| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
O(1)终于搞出来了..思路:
1. i属于哪个区间[10^(k-1),10^k-1], 也就是n那个区间有几位数
long long map[]={0,45,9045,1395495,189414495,(long long)(2E31-1)};
我另外写了个程序算出来的..汗
2. i<=map[k], 纸上算出来一个式子, 根据h可以得出map[k]某个区间里第h行的末尾是第n个digits, 比如
123..9899100
123..9899100101
123..9899100101102
123..9899100101102103
当h=4时(第4行), n等于([103的3]到开始[123的1]有多少位digits)
反过来可以由已知的n求出h
这个h不一定是整数, 但是由于函数n=f(h)是递增的, 所以根据h的整数位可以得出要求的digit在哪一行内
h=sqrt(2*n/k+(0.5+map2[k-1]/k)^2-0.5-map2[k-1]/k
map2[k]存放了 1234..k个9有多少位数
3. 根据行数算出要求的digit是哪一行的第几位, 现在问题简化成求123..9899100..这个数列中的第几位数, 很简单了
注意第2步中
开方下来h如果是整数需要特别判断一下, 我在这磨了好久.. 因为开始试图用(int)(h-0.00001)这种方式判断整数纠缠不清.. 非常傻. 就想不起来直接判断
(实验了一下math.h的sqrt()函数对于整数的开方没有误差25.0000开方就是5.0000, 可以直接if(5==5.0000)这样)
小弟拙见..希望没有浪费大家时间
代码: (为什么用c++就WA..g++就能过, 怎么试都试不出来 高手请指点..)
#include <stdio.h>
#include <math.h>
long long pow10(long long n) {
long long a;
a=1;
while(n--)
a*=10;
return a;
}
int main() {
long long map[]={0,45,9045,1395495,189414495,(long long)(2E31-1)};
long long map2[]={0,9,189,2889,38889}; //how many digits does {1 2 3 4 ... 99...9} have
long long N,n,k,x,l,number,result,digit,k_;
double h;
scanf("%lld",&N);
while(N--) {
scanf("%lld",&l);
for(k=1;l>map[k];k++);
n=l-map[k-1];
h=sqrt((double)2*n/k+(0.5+(double)map2[k-1]/k)*(0.5+(double)map2[k-1]/k))-0.5-(double)map2[k-1]/k;
if(h==(int)h)
x=h;
else
x=(int)h+1;
n=n-map2[k-1]*(x-1)-(x-1)*x/2*k;
for(k_=1;map2[k_]<n;k_++); //area's number of digits
n-=map2[k_-1];
number=pow10(k_-1)+(n-1)/k_;
digit=k_-(n-1)%k_;
result=number/pow10(digit-1)%10;
printf("%lld\n",result);
}
return 0;
}
Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator