产生数 洛谷p1037

题目描述

给出一个整数 n(n<10^30) 和 k 个变换规则(k<=15)。

规则:

一位数可变换成另一个一位数:

规则的右部不能为零。

例如:n=234。有规则(k=2):

2->5

3->6

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

234 534 264 564 共 4 种不同的产生数

问题:

给出一个整数 n 和 k 个规则。

求出:

经过任意次的变换(0次或多次),能产生出多少个不同整数。

仅要求输出个数。

输入输出格式

输入格式:

键盘输人,格式为:

n k x1 y1 x2 y2 ... ...

xn yn

输出格式:

屏幕输出,格式为:

一个整数(满足条件的个数):

输入输出样例

输入样例#1:

234 2

2 5

3 6

输出样例#1:

4

 

设F[i]表示从数字i出发可以变换成的数字个数(这里的变换可以是直接变换,也可以是间接变换,比如样例中的1可以变换成2,而2又可以变换成3,所以1也可以变换成3;另外自己本身不变换也是一种情况)。那么对于一个长度为m位的整数a,根据乘法原理,能产生的不同的整数的个数为:F[a[1]]*F[a[2]]*F[a[3]]*…*F[a[m]]。

floyd+高精度秒杀.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
struct bign{
	int l,w[100005];
	bign(){
		l=1;
		memset(w,0,sizeof(w));
	}
	bign(int x){
		l=0;
		memset(w,0,sizeof(w));
		while(x){
			w[l]=x%10;
			x/=10;
			++l;
		}
	}
	bool operator <(bign& x){
		int i;
		if(l<x.l) return 1;
		if(l>x.l) return 0;
		for(i=l-1;i>=0;i--){
			if(w[i]>x.w[i]) return 0;
			if(w[i]<x.w[i]) return 1;
		}
		return 0;
	}
	bign operator *(bign& x){
		int i,j,tmp;
		bign ans;
		ans.l=l+x.l;
		for(i=0;i<l;i++){
			for(j=0;j<x.l;j++){
				tmp=ans.w[i+j]+w[i]*x.w[j];
				ans.w[i+j+1]=tmp/10;
				ans.w[i+j]=tmp%10;
			}
		}
		while(ans.l&&!ans.w[ans.l-1]) ans.l--;
		return ans;
	}
	void write(){
		int i;
		if(!l) puts("0");
		else{
			for(i=l-1;i>=0;i--){
				printf("%d",w[i]);
			}
			printf("\n");
		}
	}
};
int d[10][10],f[10];
bign ff[10];
void floyd()
{
	int i,j,k;
	for(i=0;i<=9;i++){
		for(j=0;j<=9;j++){
			for(k=0;k<=9;k++){
				d[j][k]=d[j][k]|(d[j][i]&d[i][k]);
			}
		}
	}
}
int main()
{
	string a;
	int k,i,j,u,v;
	bign ans;
	ans=1;
//	ans.write();
	cin>>a;
	scanf("%d",&k);
	for(i=1;i<=k;i++){
		scanf("%d%d",&u,&v);
		d[u][v]=1;
	}
	for(i=0;i<=9;i++) d[i][i]=1;
	floyd();
	for(i=0;i<=9;i++){
		for(j=0;j<=9;j++){
			if(d[i][j]){
				f[i]++;
			}
		}
		ff[i]=f[i];
	}
	for(i=0;i<a.length();i++){
		ans=ans*ff[(int)(a[i]-'0')];
	}
	ans.write();
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值