【构造题】zoj 2019.01月赛 E.Little Sub and Mr.Potato's Math Problem NO. 4085

Little Sub and Mr.Potato's Math Problem


Time Limit: 2 Seconds      Memory Limit: 65536 KB


Little Sub loves math very much. He enjoys counting numbers.

One day, Mr.Potato gives him an interesting math problem. Please help Little Sub solve this problem.

Let's sort the integers  according to alphabetical order. For example, when , the order should be: .

We define  as the position of number  in the sorted  numbers. For example, .

Given  and , please find the smallest  such that .

Input

There are multiple test cases. The first line of the input contains an integer  (), indicating the number of test cases. For each test case:

The first and only line contains two integers  and  (, ).

Output

For each test case, please output the answer in one line. If there is no such , please output "0" (without quotes).

Sample Input

2
2 4
10000001 100000000

Sample Output

11
1000000088888880

Author: ZHANG, Zhihuan
Source: ZOJ Monthly, January 2019
 

给你k,m ,k这个数按照字典序排列在第m位 ,问你这个序列最小是多长

按照字典序排列

比如130 1000这组数据

1-1 在前面  有1个

10-13 在前面 有4个

100-129 在前面 有30个 //注意如果到了该数的长度及以上需要-1;

判完该数的长度还是不够 (注意,至少要有30+4+1个数在前面,所以要是m<=35,根本不可能组成序列,直接输出0)

继续

1000-1299 在前面 有300个

还不够 继续

10000-12999 在前面 有3000个

够了

那么这个序列最小长度就应该书是10000+(1000-300-30-4-1-1)-1=10663                                           

一定要排在前面的335个,自己位置保留一个,那么从10000开始要1000-335-1=664个

所以答案是10663

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int pos;
int a[18],b[18];
int flag;
void cal(ll n)
{
    while(n)
    {
        a[++pos]=n%10;
        n/=10;
    }
    for(int i=1;i<=pos;i++)
    {
        b[i]=a[pos-i+1];
        if(i==1)
        {
            if(b[i]==1)
            flag++;
        }
        else
        {
            if(b[i]==0)
            {
                flag++;
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        flag=0;
        pos=0;
        memset(a,0,sizeof a);
        ll num=0;
        ll n,m;
        scanf("%lld%lld",&n,&m);
        m--;
        cal(n);
        ll p=1,q;
        int f=0;
        for(int i=1;i<=pos;i++)
        {
            if(i==1) p=1;
            else p*=10;

            if(i!=pos)
            {
                for(int j=1;j<=i;j++)
                {
                    if(j==1) q=b[j];
                    else q=q*10+b[j];
                }
            }
            else
            {
                for(int j=1;j<=i;j++)
                {
                    if(j==1) q=b[j];
                    else q=q*10+b[j];
                }
                q--;
            }

            num+=q-p+1;
        }
        if(num>m) f=1;
        if(flag==pos&&(int)m+1==flag)
        {
            printf("%lld\n",n);
            continue;
        }
        else if(flag==pos&&q<p)
        {
            printf("0\n");
            continue;
        }
        //cout<<p<<" "<<q<<" "<<num<<" "<<m<<endl;

        if(num==m)
        {
            cout<<n<<endl;
            continue;
        }

        while(1)
        {
            p=p*10;
            q=q*10+9;
            if(num+q-p+1<m)
            {
                num+=q-p+1;
                continue;
            }
            else
            {
                p=p/10;
                q=(q-9)/10;
                break;
            }
        }
        //cout<<pos<<" "<<flag<<endl;
        p=p*10;
        p+=m-num-1;
        if(flag!=pos&&!f)
        {
            printf("%lld\n",p);
        }
        else
        {
            printf("0\n");
        }

    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值