洛谷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个整数(满足条件的个数):

输入输出样例

输入 #1

234 2
2 5
3 6

输出 #1

4

上来二话不说直接爆搜,成功地MLE了4个点,剩下的一个点也成功地WA掉了,震惊之余看了看数据范围,算了一下最多有10^{30}个不同的数...(不WA,不MLE才怪...)

切换思路,仔细想了一下,因为没有变成0的可能,所以数的位数不会改变,所以所有位上的可能出现的数的个数的乘积就是答案(好绕)

首先遍历边,把所有数可能改变的数的个数记录下来. 然后直接遍历原字符串把每一位可能出现的数的个数乘起来就行了。要用到高精度乘法。。。

ACCODE

#include <iostream>
#include <cstring>
using namespace std;
struct node
{
	int to;
	int nxt;
}edge[20];
int head[20];
int vis[20];
int k[20];             //记录每种数字可能变成的数字的个数
int cnt=0;
int ans[101];
int len=0;
void addedge(int from,int to)
{
	edge[cnt]={to,head[from]};
	head[from]=cnt++;
}


void dfs(int p)
{
	for(int i=head[p];i!=-1;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(vis[v]) continue;
		vis[v]=1;
		dfs(v);	
	}
}

void mul(int t)
{
	int j=0;
	for(int i=0;i<=len;i++)
	{
		ans[i]*=t;
		ans[i]+=j;
		j=ans[i]/10;
		ans[i]%=10;
	}
	while(j)
	{
		ans[++len]=j;
		j/=10;
		ans[len]%=10;
	}
}                                    //高精乘(写的好丑。。。)

void getk()
{
	for(int i=0;i<10;i++)
	{
		memset(vis,0,sizeof(vis));
		vis[i]=1;
		dfs(i);
		for(int j=0;j<10;j++)
		if(vis[j])
		k[i]++;
	}
}

void getans(string a)
{
	ans[0]=1;
	for(int i=0;i<a.size();i++)
	{
		int t=a[i]-'0';
		mul(k[t]);
	}
	for(int i=len;i>=0;i--)
	cout<<ans[i];
}

int main()
{
	memset(head,-1,sizeof(head));
	int n;
	string a;
	cin>>a>>n;
	for(int i=0;i<n;i++)
	{
		int c,d;
		cin>>c>>d;
		addedge(c,d);
	}
	getk();
	getans(a);
	return 0;
}
发布了30 篇原创文章 · 获赞 9 · 访问量 1317

猜你喜欢

转载自blog.csdn.net/Zhang_sir00/article/details/99867489