产生数

产生数 ⁡ \operatorname{产生数}

题目链接: luogu P1037 ⁡ \operatorname{luogu\ P1037} luogu P1037

题目

给出一个整数 n   ( n < 1 0 30 ) n\ (n \lt 10^{30}) n (n<1030) k k k 个变换规则 ( k ≤ 15 k \le 15 k15 )。

规则:

一位数可变换成另一个一位数。
规则的右部不能为零。
例如: n = 234 n=234 n=234 。有规则( k = 2 k=2 k=2 ):

  1. 2 2 2 -> 5 5 5
  2. 3 3 3 -> 6 6 6

上面的整数 234 234 234 经过变换后可能产生出的整数为(包括原数):

  1. 234 234 234
  2. 534 534 534
  3. 264 264 264
  4. 564 564 564

4 4 4 种不同的产生数。

现在给出一个整数 n n n k k k 个规则。求出经过任意次的变换( 0 0 0 次或多次),能产生出多少个不同整数。

仅要求输出个数。

输入

第一行两个整数 n , k n,k n,k

接下来 k k k 行,每行两个整数 x i , y i x_i,y_i xi,yi

输出

输出能生成的数字个数。

样例输入

234 2
2 5
3 6

样例输出

4

思路

这道题就是一道 dfs 加高精。

我们可以对于 n n n 的每一位看看这一位可以转换到多少个数(包括本身),然后用高精乘把每一位可以转换到的数的个数都乘起来就是答案了。

有一点要注意的就是,最高位不能是 0 0 0 ,因为题目要求了。

代码

#include<cstdio>
#include<cstring>

using namespace std;

int n[101], k, num, x, y, turn[11][11], ans[1001], kk;
bool in[11];

int read() {//读入n
	int an;
	char c = getchar();
	
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') {
		n[++kk] =  c - '0';
		c = getchar();
	}
	
	return an;
}

void work(int now) {//找到能转换到的数
	if (!in[now]) num++;
	in[now] = 1;
	for (int i = 1; i <= turn[now][0]; i++)
		if (!in[turn[now][i]]) work(turn[now][i]);
}

int main() {
	ans[1] = 1;
	ans[0] = 1; //初始化
	
	read();
	scanf("%d", &k);//读入
	
	for (int i = 1; i <= k; i++) {
		scanf("%d %d", &x, &y);//读入
		if (x != y) turn[x][++turn[x][0]] = y;//记录转换
	}
	
	for (int i = 1; i <= kk; i++) {
		memset(in, 0, sizeof(in));//初始化
		num = 0;
		
		work(n[i]);//找到能转换到的数的个数
		
		if (i == 1 && in[0]) num--;//最高位不可以是0(题目要求)
		
		for (int i = 1; i <= ans[0]; i++)//高精乘
			ans[i] *= num;
		for (int i = 1; i <= ans[0] + 1; i++) {
			ans[i + 1] += ans[i] / 10;
			ans[i] %= 10;
		}
		if (ans[ans[0] + 1]) ans[0]++;//进位
	}
	
	for (int i = ans[0]; i >= 1; i--)
		printf("%d", ans[i]);//输出
	
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值