POJ1019--Number Sequence

20 篇文章 0 订阅

设begin[k]为Sk的第一个元素,根据题意首先可以对begin[k]打表,k最大为31628,然后二分查找。

额,感觉可以推下公式。

当1<=k<=9时,begin[k] = begin[1]+k*(k-1)/2。

当10<=k<=99时,begin[k] = begin[10]+k*(k-10)。

当100<=k<=999时,begin[k] = begin[100]+(3k+81)(k-100)/2。

当1000<=k<=9999时,beigin[k] = begin[1000]+(k-1000)(2k+891)。

当10000<=k<=99999时,begin[k] = begin[10000]+(5k+27783)(k-10^4)/2。

根据上述公式,可以由输入pos推出pos处在哪个Sk,因为定点的问题,解方程时对结果加0.5再向0方向取整,可以保证求出结果只会是k或者k+1,再判定一下即可。


#include<cstdio>
#include<cmath>
#define k_pos1(k) ((k)*((k)-1)/2)
#define k_pos2(k) ((k)*((k)-10))
#define k_pos3(k) ((3*(k)+81)*((k)-100)/2)
#define k_pos4(k) ((2*(k)+891)*((k)-1000))
#define k_pos5(k) ((5*(k)+27783)*((k)-10000)/2)

int judge(long long k,int pos,int n)   //将k转换成64位,防止乘法溢出
{
    switch(n)
    {
        case 1: if(pos >= k_pos1(k))
                    return pos-k_pos1(k)+1;
                else
                    return pos-k_pos1(k-1)+1;
        case 2: if(pos >= k_pos2(k))
                    return pos-k_pos2(k)+1;
                else
                    return pos-k_pos2(k-1)+1;
        case 3: if(pos >= k_pos3(k))
                    return pos-k_pos3(k)+1;
                else
                    return pos-k_pos3(k-1)+1;
        case 4: if(pos >= k_pos4(k))
                    return pos-k_pos4(k)+1;
                else
                    return pos-k_pos4(k-1)+1;
        case 5: if(pos >= k_pos5(k))
                    return pos-k_pos5(k)+1;
                else
                    return pos-k_pos5(k-1)+1;
    }
}

int calc_pos(int pos,int n)
{
    switch(n)
    {
        case 1: return judge(floor(sqrt(2.0*pos+0.25)+0.5+0.5),pos,n);
        case 2: return judge(floor(sqrt(pos*1.0+25.0)+5+0.5),pos,n);
        case 3: return judge(floor(sqrt((pos*2.0+8100+3.0*73*73.0/4.0)/3.0)+73/2+0.5),pos,n);
        case 4: return judge(floor(sqrt((pos*1.0+891000+1109.0*1109.0/8.0)/2.0)+1109/4+0.5),pos,n);
        case 5: return judge(floor(sqrt((pos*2.0+277830000+22217.0*22217.0/20.0)/5.0)+2221.7+0.5),pos,n);
    }
}

int calc_digit(int num,int pos)
{
    while(--pos) num /= 10;
    return num%10;
}

int main()
{
    int T;
    int posNum;
    int maxDigitNum,digitNum;
    int pos,strPos;
    int beginPos[6] = {0,1,46,9046,1395496,189414496};
    int num[6] = {0,1,10,100,1000,10000};
    int singleStrPos[6] = {0,1,10,190,2890,38890};
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&pos);
        digitNum = maxDigitNum = 5;
        while(pos < beginPos[maxDigitNum]&&maxDigitNum--);
        strPos = calc_pos(pos-beginPos[maxDigitNum],maxDigitNum);
        while(strPos < singleStrPos[digitNum]&&digitNum--);
        posNum = (strPos-singleStrPos[digitNum])/digitNum+num[digitNum];
        printf("%d\n",calc_digit(posNum,digitNum-(strPos-singleStrPos[digitNum])%digitNum));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值