您的位置:首页 > 产品设计 > UI/UE

UVa 10706 Number Sequence

2013-06-01 20:46 281 查看
/*
思路: 二分法求出k值, 再对sk二分法求出所在数值, 最后确定所在位
*/
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int s1[] = {0, 45, 9045, 1395495, 189414495}; // 前0项 前9项 前99项 前999项 前9999项位数和
int s2[] = {0, 9, 189, 2889, 38889}; // s0 s9 s99 s999 s9999的位数
int s3[] = {0, 9, 99, 999, 9999};

void getxy(int &x, int &y, int d)
{
x = 1;
y = 9;
while(d-->1) {
x *= 10;
y = y*10 + 9;
}
}

void guess(int n, int d)
{
int x, y;
getxy(x, y, d); //获得二分法上下界

//二分法算出k值(存在x中)
double sum = n - s1[d-1]; // sum开始计算的位数
int a = s3[d-1]; //a, b, sf 求和参数
int b = s2[d-1];
int sf = b + d; //sf第一项位数
double s;
while(x < y) {
int m = x + (y-x)/2;
int sm = (m - a)*d + b;
s = floor(1.0*(sm+sf)*(m-a)/2 + 1e-9); //等差数列求和公式
if(abs(s - sum) < 1e-9) {
x = m; break;
}
if(s - sum > 1e-9) y = m;
else x = m+1;
}
int sb = (x-a-1)*d + b; //x的前一列 s(k-1)所有位数
s = floor(1.0*(sb+sf)*(x-a-1)/2 + 1e-9);
int left = floor(sum - s + 1e-9);
for(d=0; d<5; d++) {
if(left <= s2[d]) break;
}
left -= s2[d-1];
//二分法算出Sk中的第几项
getxy(x, y, d);
int cnt;
int sx = x;
while(x < y) {
int m = x + (y-x)/2;
cnt = (m-sx+1)*d; //等差数列求和公式
if(cnt == left) {
x = m; break;
}
if(cnt > left) {
y = m;
} else {
x = m+1;
}
}
//判断在x第几位
cnt = left - (x-sx)*d -1;
char buff[6];
sprintf(buff, "%d", x);
printf("%c\n", buff[cnt]);
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
int n;
while(T--) {
scanf("%d", &n);
int d;
for(d=0; d<5; d++) {
if(n <= s1[d]) break;
}
guess(n, d);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: