LuoGu P1037 产生数【DFS|大数乘法】

题目链接
在这里插入图片描述
这题一开始陷入了一个死区,我们可以使用简单的bfs来对输入的字符串进行遍历,一位一位的进行修改,用map来防止重复状态计数,那么我们最大可能有多少结果呢?这是这道题的重点,下列算法TLE了

#define inf 0x3f3f3f3f
#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 105

string s; 
int k, a, b;
vec rs[MAX];
int main() {
	cin >> s >> k;
	for (int i = 0; i < k; i++) {
		cin >> a >> b;
		if (b != 0)rs[a].push_back(b);//a can be converted to b
	}
	queue<string> q; map<string, bool> ma;
	ma[s] = 1; int res = 1; q.push(s);
	while (!q.empty()) {
		string t = q.front(), n = t; q.pop();
		for (int i = 0; i < t.size(); i++) {
			int id = t[i] - '0';
			if (rs[id].size() > 0) {
				for (int j = 0; j < rs[id].size(); j++) {
					n = t;
					n[i] = rs[id][j] + '0';
					if (ma.find(n) == ma.end()) {
						ma[n] = 1; res++;
						q.push(n);
					}
				}
			}
		}
	}
	cout << res << endl;
}

如何分析我们可能会产生多少结果,我们需要注意到

位 的 变 化 是 相 互 独 立 的 , 相 互 不 影 响 位的变化是相互独立的,相互不影响
也就是说,只要我们统计出每一位有多少种变化次数,然后将他们全部乘起来即可。到这里基本上就可以了,如果数字2能变成3,那么我们建图2->3,dfs这个图就能找到每个数字最多变化多少种,然后高精度乘法即可

#define inf 0x3f3f3f3f
#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 105

string s; 
int k, a, b, vis[10], cnt, num[10];
vec rs[MAX];

void dfs(int k) {
	for (int i = 0; i < rs[k].size(); i++) {
		int v = rs[k][i];
		if (!vis[v]) {
			vis[v] = 1; cnt++;
			dfs(v); 
		}
	}
}

string mul(string s1, string s2) {
	int l1 = s1.size(), l2 = s2.size(), res = 0, mod = 0;
	vec v(l1 + l2 - 1), v1, v2;
	for (int i = l1 - 1; i >= 0; i--)v1.push_back(s1[i] - '0');
	for (int i = l2 - 1; i >= 0; i--)v2.push_back(s2[i] - '0');
	for (int i = 0; i < l1; i++)
		for (int j = 0; j < l2; j++)
			v[i + j] += v1[i] * v2[j];

	for (int i = 0; i < l1 + l2 - 1; i++) {
		res = mod + v[i];
		v[i] = res % 10, mod = res / 10;
	}
	while (mod > 0) {
		v.push_back(mod % 10); mod /= 10;
	}
	string r;
	for (int i = v.size() - 1; i >= 0; i--) {
		r += to_string(v[i]);
	}
	return r;
}
int main() {
	cin >> s >> k;
	for (int i = 0; i < k; i++) {
		cin >> a >> b;
		if (b != 0)rs[a].push_back(b);//a can be converted to b
	}
	for (int i = 0; i < 10; i++) {
		memset(vis, 0, sizeof(vis)); cnt = 0;
		num[i] = 1; vis[i] = 1;
		dfs(i);
		num[i] += cnt;
	}

	string res = "1";
	for (int i = 0; i < s.size(); i++) {
		res = mul(res, to_string(num[s[i] - '0']));
	}
	cout << res << endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值