Educational Codeforces Round 23#C. Really Big Numbers

来源:互联网 发布:java 读取上传文件流 编辑:程序博客网 时间:2024/06/07 11:00

题意:

1. 一个数减去他每一位的数后仍大于s,表示这个数是真大数

2. 求1~n中有多少个真大数

3. 范围是1<=n<=1e18

解法:

1. 列举几种样例后我们可以发现,真大数都是连续的,除非没有,也就是说只要找到第一个,那从这个开始一直到n都是真大数

2. 范围比较大,所以这里有个简单的思路是用二分法(见第二段AC代码)

1. 以下介绍第二种思路:

2. 列举大量样例后发现一个规律,真大数总是从整十开始。9-9=0 。10-1=9,11-2=9,19-10=9 。20-2=18,90-9=81 。100-1=99 。1000-1=999 ……

3. 第二个规律(逆推):8430-15=8415 。8415=999*8+99*4+9*3 。刚好是第一个真大数的每一位数(除了个位上的0之外)。所以我们可以从给出的s=8415进行逆推得到8430,而8416逆推得到8440

4. 注意:当s=98时,用上面的算法得到110并不是正确结果100,因为98/9=10>9,也就是说当整除结果出现10时,此时不再判断最后一个余数是否大于0(见代码中的flag标记)


以下是我的AC代码:

#include <iostream>#define LL long longusing namespace std;int main(){    LL n,s;    cin >> n >> s;    LL sum=0,a=999999999999999999;    int flag=0;    while(a)    {        LL b=s/a;        if(b>9)            flag=1;        sum=sum*10+b;        s-=b*a;        a/=10;    }    sum*=10;    if(s && !flag)        sum+=10;    a=sum<=n?n-sum+1:0;    cout << a << endl;    return 0;}

#include <iostream>using namespace std;bool my_count(long long mid,long long s){    long long a=mid;    while(a)    {        mid-=a%10;        a/=10;    }    if(mid>=s)        return true;    else        return false;}long long binary(long long a,long long b){    long long left=0,right=a,mid;    while(left<=right)    {        mid=(left+right)/2;        if(my_count(mid,b) && !my_count(mid-1,b))            return mid;        else if(my_count(mid,b) && my_count(mid-1,b))            right=mid-1;        else if(!my_count(mid,b) && !my_count(mid-1,b))            left=mid+1;    }    return 0;}int main(){    long long n,s;    cin >> n >> s;    long long flag=binary(n,s);    if(flag)        cout << n-flag+1 << endl;    else        cout << 0 << endl;    return 0;}