首先通过初步阅读题目,就可以发现这是一个关于排列组合的问题,但仔细研读以及通过阅读题解后发现,这里存在一个隐含的条件,例如1->2,2->3,那么1也可以通过两次变化变成3,这里就可以初步发现这个问题实际已经转化成了一个图论的问题,翻译一下就是有若干个城市,现在已知若干条道路可以将其中的一些城市连接起来,问你其中全部可以互相到达的城市,这里就可以用到弗洛伊德算法。`
inline void floyd() { //弗洛伊德
for (int k = 0;k <= 9;k++)
for (int i = 0;i <= 9;i++)
for (int j = 0;j <= 9;j++) vis[i][j] = vis[i][j] || (vis[i][k] && vis[k][j]);
}
这大概就是一个最最基础的弗洛伊德算法的模型,简单解释一下就是看看i,j之间是否通过k之间可以联系起来。我个人觉得这里最需要注意的一点是中间值k要放在最开始进行遍历。
然后这里还要用到高精度的一些东西,因为这里的数据范围已经远远超过了long long 所以必须要用到高精度的东西。
int len = 2; num[1] = 1;
for (int i = 0;i < (int)str.length();i++) //这里是你输入的这个数的长度{
for (int j = 1;j <= 100;j++) num[j] *= f[str[i]-'0'];//这里f数组代表的每个数的通航数量
for (int j = 1;j <= 100;j++)
if (num[j] >= 10) { //进位
num[j+1] += num[j]/10;
num[j] %= 10;
}
while (num[len]) len++; //求出长度
}
for (int i = len-1;i >= 1;i--) cout << num[i]; //输出
总结起来就是一句话,先是用弗洛伊德算法算出每个数与之相连(包括它本身)数的个数,然后实际上就是遍历你输入的这段数,把他们对应相连数的个数全部乘起来即可,就算没有数与之相连,那么就是1,不影响最终的结果。最后贴上完整代码
#include <iostream>
#include <string>
using namespace std;
string str;
int k,vis[10][10],f[10],num[101];
inline void floyd() { //弗洛伊德
for (int k = 0;k <= 9;k++)
for (int i = 0;i <= 9;i++)
for (int j = 0;j <= 9;j++) vis[i][j] = vis[i][j] || (vis[i][k] && vis[k][j]);
}
int main (){
cin >> str >> k;
while (k--) {
int a,b;
cin >> a >> b;
vis[a][b] = true; //a可以变成b
}
for (int i = 0;i <= 9;i++) vis[i][i] = true; //自己可以变成自己
floyd();
for (int i = 0;i <= 9;i++)
for (int j = 0;j <= 9;j++)
if (vis[i][j]) f[i]++; //求出i可以变成多少种数字
int len = 2; num[1] = 1;
for (int i = 0;i < (int)str.length();i++) { //高精度
for (int j = 1;j <= 100;j++) num[j] *= f[str[i]-'0'];
for (int j = 1;j <= 100;j++)
if (num[j] >= 10) { //进位
num[j+1] += num[j]/10;
num[j] %= 10;
}
while (num[len]) len++; //求出长度
}
for (int i = len-1;i >= 1;i--) cout << num[i]; //输出
return 0;
}