P1037 [NOIP2002 普及组] 产生数

# [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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值