题目链接

https://www.dotcpp.com/oj/problem1492.html

题目大意

每个数(0 ~ 9)可以变换成其他的数(除本身外0 ~ 9)。
给定一个数,问这个数可以有多少种形式(包含原形)

解题思路

思路很简单,把这个数中每一位数可以变换的种数相乘,得到答案。
难点1:如何统计每个数可以变换的种数(含自己)?
难点2:最终答案的最大可能为:每一位数都有10种变换(含自己),答案是10^30,比longlong大,怎么表达这个数?
难点2解决:这么大的数,自然相当高精度乘法(高精度*低精度),解决!
难点1解决:给出的变换规则,相当于一个图,关系是有向边,a能变成b,意味着a到b存在一条有向边。存下所有边之后,我们可以dfs遍历并统计其能到达的所有点的个数,用数组记录下来。进行高精度乘法的时候使用。

高精度*低精度板子

如果不会高精度乘法,建议先看看通过数组实现高精度的板子,再看容器实现的板子

//函数部分
vector<int> mul(vector<int> a,int b){
    vector<int> c;
    int t=0;
    for(int i=0;i<a.size();i++){
        t=a[i]*b+t;
        c.push_back(t%10);
        t/=10;
    }
    while(t){//把剩余没保存在vector中的数,保存进去
        c.push_back(t%10);
        t/=10;
    }
    return c;
}
//主函数部分
vector<int> res;
res.push_back(1);
for(int i=1;i<=len;i++){
        res=mul(res,k);//表示k与res相乘
}

大佬代码

#include<bits/stdc++.h>
using namespace std;
int len,cnt,k,p,q;
int vis[10],num[10],a[50];
vector<int> v[10];
vector<int> res;
char s[50];

void dfs(int x){
    for(int i=0;i<v[x].size();i++){
        int next=v[x][i];
        if(vis[next]) continue;
        cnt++;
        vis[next]=1;
        dfs(next);
    }
    return ;
}
vector<int> mul(vector<int> a,int b){
    vector<int> c;
    int t=0;
    for(int i=0;i<a.size();i++){
        t=t+a[i]*b;
        c.push_back(t%10);
        t/=10;
    }
    while(t){
        c.push_back(t%10);
        t/=10;
    }
    return c;
}
int main(){
    cin>>s+1>>k;
        //存边
    for(int i=1;i<=k;i++){
        cin>>p>>q;
        v[p].push_back(q);
    }
    //逆置字符串
    len=strlen(s+1);
    for(int i=1;i<=len;i++)
        a[len-i+1]=s[i]-'0';
    //dfs
    for(int i=0;i<=9;i++){
        cnt=1;//初始化的时候直接加上自己这个点
        memset(vis,0,sizeof vis);
        vis[i]=1;//勿忘,但其实好像对本题的数据没影响
        dfs(i);
        num[i]=cnt;//num用于存数字i可变种数
    }
    //*
    res.push_back(1);//勿忘
    for(int i=1;i<=len;i++){
        res=mul(res,num[a[i]]);
    }
    //输出 
    for(int i=res.size()-1;i>=0;i--)
        cout<<res[i];
    cout<<endl;
    return 0;
}

我的代码

和大佬的差别在于dfs。我的比较混乱,多用了个set容器。其他部分一样。
所以,可以忽略我的代码

#include<bits/stdc++.h>
using namespace std;
const int N=50;
int fa;
int vis[10];
vector<int> a[10];
int cnt[N];
set<int> num[10];
char n[N];
int c[N];
vector<int> mul(vector<int> a,int b){
    vector<int> c;
    int t=0;
    for(int i=0;i<a.size();i++){
        t=a[i]*b+t;
        c.push_back(t%10);
        t/=10;
    }
    while(t){
        c.push_back(t%10);
        t/=10;
    }
    return c;
}
void dfs(int x){
    for(int i=0;i<a[x].size();i++){
        int tmp=a[x][i];
        if(tmp==fa || vis[tmp]) continue;
        num[fa].insert(tmp);
        vis[tmp]=1;
        dfs(tmp);
    }
    return ;
}
int main(){
    int k,p,q;
    cin>>n+1>>k;
    //存边 
    for(int i=1;i<=k;i++){
        cin>>p>>q;
        a[p].push_back(q);
    }
    //找到每个数能变成的全部数    
    for(int i=0;i<=9;i++){
        fa=i;
        memset(vis,0,sizeof vis);
        vis[i]=1; 
        dfs(i);
    }
    //计算每个数能变成其他数的个数        
    for(int i=0;i<=9;i++)
        cnt[i]=num[i].size();
    //逆置字符串 
    int len=strlen(n+1);
    for(int i=1;i<=len;i++)    
        c[len-i+1]=n[i]-'0';
    //高精度乘法 
    vector<int> res;
    res.push_back(1);
    for(int i=1;i<=len;i++){
        res=mul(res,cnt[c[i]]+1);
    }
    //输出 
    for(int i=res.size()-1;i>=0;i--)
        cout<<res[i];
    cout<<endl;

    return 0;
} 

总结

这是我们昨天蓝桥训练的一道题,昨天还不会,今天看完高精度,思路都清晰了,直接AC,神了!