洛谷 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
如果本题用搜索,搜索的范围会很大(因为n可能有30位!),显然无法在规定的时间内出解。而我们注意到本题只需计数而不需要求出具体方案,所以我们稍加分析就会发现,可以用乘法原理直接进行计数。
设F[i]表示从数字i出发可以变换成的数字个数(这里的变换可以是直接变换,也可以是间接变换,比如样例中的1可以变换成2,而2又可以变换成3,所以1也可以变换成3;另外自己本身不变换也是一种情况)。那么对于一个长度为m位的整数a,根据乘法原理,能产生的不同的整数的个数为:F[a[1]]*F[a[2]]*F[a[3]]*…*F[a[m]]。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 6 const int MAXN = 100010; 7 8 int f[11][11]={0}; 9 10 char n[101]; 11 12 int m,num[11],ans[MAXN]; 13 14 inline void read(int&x) { 15 int f=1;x=0;char c=getchar(); 16 while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();} 17 while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-48;c=getchar();} 18 x=x*f; 19 } 20 21 inline void mul(int x) { 22 ++ans[0]; 23 for(int i=1;i<=ans[0];i++) 24 ans[i]=ans[i]*x; 25 for(int i=1;i<=ans[0];i++) 26 if(ans[i]>=10) { 27 ans[i+1]+=ans[i]/10; 28 ans[i]%=10; 29 } 30 while(ans[0]>1&&!ans[ans[0]]) ans[0]--; 31 return; 32 } 33 34 int main() { 35 scanf("%s",n); 36 read(m); 37 for(int i=1;i<=m;i++) { 38 int x,y; 39 read(x);read(y); 40 f[x][y]=1; 41 } 42 for(int i=0;i<=9;i++) f[i][i]=1; 43 for(int k=0;k<=9;k++) 44 for(int i=0;i<=9;i++) 45 for(int j=0;j<=9;j++) 46 if(f[i][j]||f[i][k]&&f[k][j]) 47 f[i][j]=1; 48 for(int i=0;i<=9;i++) 49 for(int j=0;j<=9;j++) 50 if(f[i][j]) num[i]++; 51 ans[1]=1;ans[0]=1; 52 int len=strlen(n); 53 for(int i=0;i<len;i++) mul(num[n[i]-'0']); 54 for(int i=ans[0];i>=1;i--) printf("%d",ans[i]); 55 printf("\n"); 56 return 0; 57 }
作者:乌鸦坐飞机
出处:http://www.cnblogs.com/whistle13326/
新的风暴已经出现
怎么能够停止不前
穿越时空 竭尽全力
我会来到你身边
微笑面对危险
梦想成真不会遥远
鼓起勇气 坚定向前
奇迹一定会出现