# [NOIP2002 普及组] 产生数
## 题目描述
给出一个整数 $n$ 和 $k$ 个变换规则。
规则:
- 一位数可变换成另一个一位数。
- 规则的右部不能为零。
例如:$n=234,k=2$。有以下两个规则:
- $2\longrightarrow 5$。
- $3\longrightarrow 6$。
上面的整数 $234$ 经过变换后可能产生出的整数为(包括原数):
- $234$。
- $534$。
- $264$。
- $564$。
共 $4$ 种不同的产生数。
现在给出一个整数 $n$ 和 $k$ 个规则。求出经过任意次的变换($0$次或多次),能产生出多少个不同整数。
仅要求输出个数。
## 输入格式
第一行两个整数 $n,k$,含义如题面所示。
接下来 $k$ 行,每行两个整数 $x_i,y_i$,表示每条规则。
## 输出格式
共一行,输出能生成的数字个数。
## 样例 #1
### 样例输入 #1
```
234 2
2 5
3 6
```
### 样例输出 #1
```
4
```
## 提示
对于 $100\%$ 数据,满足 $n \lt 10^{30}$,$k \le 15$。
**【题目来源】**
NOIP 2002 普及组第三题
思路:
给定某一种变换后,寻找是否可能造成一个间接变换:
1-2
2-3
那么就造成一个间接变换1-3
所以Floyd直接跑一遍得到数字0-9的变换种类,然后根据读入的数据也就是整数n的每一位是什么数字,这个数字有几种变换,使用乘法原理即可(注意特判最高位不能为0)
(爆long long)......高精度*低精度即可
#include<bits/stdc++.h>
using namespace std;
int tag[10][10];
int d[10];
int p[1000];
int main() {
string a;
int n;
cin>>a>>n;//录入字符串和变换种类
int x,y;
for(int i=0; i<n; i++) {
cin>>x>>y;
tag[x][y]=1;//表示可以从x换到y
}
//开始寻找可以间接转换的
for(int k=0; k<=9; k++) {
for(int i=0; i<=9; i++) {
for(int j=0; j<=9; j++) {
if(tag[i][k]&&tag[k][j]) {
tag[i][j]=1;
}
}
}
}
for(int i=0; i<10; i++) {
tag[i][i]=1;//自己肯定是可以换为自己的
for(int j=0; j<10; j++) {
if(tag[i][j]) {
d[i]++;//记录一下这个数字可以有多少种变换
}
}
}
int z=0;
p[0]=1;
for(int i=0; a[i]; i++) {
z=0;
x=d[a[i]-'0'];//获得a的每一位
if(i==0&&tag[a[i]-'0'][0]) { //处理最高位不能变成0的情况
x--;
}
for(int i=0; i<500; i++) { //高精度*低精度
p[i]=(p[i]*x+z);
z=p[i]/10;
p[i]%=10;
}
}
int i=500;
while(p[i]==0)i--;
for(; i>=0; i--) {
cout<<p[i];
}
return 0;
}