【题解】产生数 (集训day3)

知识点:搜索+高精度。

大体思路:

1.  我们求出每一位可以变换的数的个数。再用乘法原理一个一个乘起来。乘的时候用高精度。

2.  怎么求每一位可以变换成哪些数呢?搜索。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

char tmp1[1009];
int k,len1;
int s[1009];//数字串n 
int cnt[1009];//cnt[i]表示i可以变换的数的个数
int num[1009][1009];//num[i][1]表示i可以变成num[i][1] 
long long ans[1009];//ans[i]表示第i位的变换总数
int vis[1009]; 
int lastans[100009],digit=1;

void dfs(int nums,int ii){
	if(vis[nums] == 1)return;//注意这里要回溯!
	
	if(vis[nums] == 0){
		vis[nums] = 1;
		ans[ii]++;
	}
	
	for(int k=1; k<=cnt[nums]; k++){
		int nown = num[nums][k];
		dfs(nown,ii);
	}
}

void init(){
	for(int i=0; i<109; i++)vis[i] = 0;
}

void mul(int tt){
	int carry=0;//进位 
	for(int i=31; i>31-digit; i--){
		int ll = lastans[i]*tt+carry;
		carry = ll/10;
		lastans[i] = ll%10;
	}
	if(carry > 0){
		digit++;
		lastans[31-digit+1] = carry;
	}
}

int main(){
	cin >> tmp1 >> k;
	len1 = strlen(tmp1);
	for(int i=0; i<len1; i++) s[i+1] = tmp1[i]-'0';
	
	for(int i=1; i<=k; i++){
		int x,y;
		cin >> x >> y;//x可以变成y 
		cnt[x]++;
		num[x][cnt[x]] = y; 
	}
	
	lastans[31] = 1;
	
	for(int i=1; i<=len1; i++){
		init();//每一次都要清空 vis 数组
		dfs(s[i],i);
		mul(ans[i]);
	}
	
	int start=1;
	for(int i=1; ; i++){//删除前导0 
		if(lastans[i] == 0)start++;
		else break;
	}
	for(int i=start; i<=31; i++)cout << lastans[i];
	return 0;
} 

我一开始用 dp,拿到了 60pts,后来发现可以是经过多次“辗转”,变成另一个数,然后就放弃了,感觉 dp 不行。不过现在觉得 dp 好像是可行的,只不过也需要用 dfs 求出来一个数可以变成多少个数。 

转移方程应该就是 $f_i=f_{i-1} \times cnt$ ($cnt$ 就是第 $i$ 个位置上的数可以变成多少个数,那个个数) 注意 $f_0=1$

 

上一篇:(hnust 1601)名字缩写(map存储前缀)


下一篇:JavaScript进行UTF-8编码与解码