CF1157A-Reachable Numbers题解

原题地址c++


题目大意:有一个函数\(f(x)\),效果是将\(x+1\)后,去掉末尾全部的\(0\),例如:数组

\(f(599)=6\),由于\(599+1=600→60→6\)函数

\(f(7)=8\),由于\(7+1=8\)spa

\(f(9)=1\),由于\(9+1=10→1\)c++11

\(f(10099)=101\),由于\(10099+1=10100→1010→101\)
咱们能够屡次进行函数\(f(x)\)的运算,从而让一个数\(x\)转换为另外一个数,例如\(10098\)能够转换为\(102\),由于\(f(f(f(10098)))=f(f(10099))=f(101)=102\)
你须要作的是给你一个数\(n\),求出\(n\)通过屡次函数\(f(x)\)的计算,能转换为几个不一样的数(包括自身)?code


首先,经过模拟样例,不可贵出一个结论:若是\(f(x)\)的结果先前已经获得,那么就表明着全部的答案已经算完。get

例如:\(n=1\)时,答案为\(9\),模拟过程以下:io

\(f(1)=2\)class

\(f(2)=3\)test

\(f(3)=4\)

\(f(4)=5\)

\(f(5)=6\)

\(f(6)=7\)

\(f(7)=8\)

\(f(8)=9\)

\(f(9)=1\)

\(f(1)=2\)

\(...\)

不难发现,当咱们算到\(f(9)=1\)时,即可以结束计算,由于很显然接着算都是获得以前算过的数,因而咱们的代码也就很容易写了。

伪代码:

bool book[];//桶,用于判断某个数是否已经算过
int f(int n)//f函数
{
    n++;
    while(!(n%10))
        n/=10;
    return n;
}
int main()
{
    for(;!book[n];n=f(n))//核心代码
    {
        book[n]=true;
        ans++;
    }
}

可是,以上的代码有一个严重的错误:book数组是要开到n级别的,而\(n \le 10^9\),很显然开这么大会MLE,因而咱们的\(STL::map\)就派上用场啦!

\(STL::map\)来代替桶,这样就能够防止空间爆炸了。

代码以下:

#pragma GCC diagnostic error "-std=c++11"
#include <cstdio>
#include <map>
using namespace std;
template<class T>void r(T &a)//快读
{
    T s=0,w=1;a=0;char ch=getc(stdin);
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getc(stdin);}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getc(stdin);}
    a=w*s;
}
template<class T,class... Y>void r(T& t,Y&... a){r(t);r(a...);}
int f(int n)
{
    n++;
    while(!(n%10))
        n/=10;
    return n;
}
map<int,bool>book;
int main()
{
    int n,ans=0;
    r(n);
    for(;!book[n];n=f(n))
    {
        book[n]=true;
        ans++;
    }
    printf("%d",ans);
    return 0;
}
相关文章
相关标签/搜索