产生数

产生数

题目描述

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

规则:

  1. 1个数字可以变换成另一个数字;
  2. 规则的右部不能为零。

例如:n=234,有规则(k=2):2 → 5、3 → 6。

234经过变换后可能产生出的整数为(包括原数):234、534、264、564,共4个不同的产生数。

给出一个整数n和k个规则。求经过任意次的变换(0次或多次),能产生出多少个不同的整数。(仅要求输出个数)


输入样例

234 2
2 5
3 6

输出样例

4


解析

这道题明显就是要求每一个数N能够间接转化成的数的数量

然后根据乘法原理扫一遍原数字,*起来就可以了

如何得到每一个数N能够间接转化成的数z的数量

这里介绍图论的观点

设有向图G , 若i点能够间接到达j点 ,那么根据题意, 数字i就能转化为j

floyd-warshall !

这个算法不用介绍了吧,不懂的话就百度,基本原理就是i点能到k点,k点能到j点,那么i就能到j (对于这道题而言

(一定不要忘记是k,i,j的顺序

话不多说上代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
string n;
int k, g[10][10];
int d[10];
void floyd() {
  for (int k = 0;k <= 9;++k) {
    for (int i = 0;i <= 9;++i) {
      for (int j = 0;j <= 9;++j) {
        g[i][j] |= g[i][k] && g[k][j];
      }
    }
  }
}
struct high {
  int a[maxn], len;
  void init() {
    len = 1;
    a[0] = 1;
  }
  void mul(int x) {
    for (int i = 0;i < len;++i) {
      a[i] *= x;
    }
    for (int i = 0;i < len;++i) {
      a[i + 1] += a[i] / 10;
      a[i] %= 10;
    }
    while (a[len]) {
      a[len + 1] += a[len] / 10;
      a[len] %= 10;
      ++len;
    }
  }
  void print() {
    for (int i = len - 1;i >= 0;--i) {
      printf("%d", a[i]);
    }
  }
};
int main() {
  cin >> n >> k;
  for (int i = 1;i <= k;++i) {
    int u, v; scanf("%d%d", &u, &v);
    g[u][v] = 1;
  }
  for (int i = 0;i <= 9;++i) g[i][i] = 1;
  floyd();
  for (int i = 0;i <= 9;++i) {
    for (int j = 0;j <= 9;++j) {
      d[i] += g[i][j];
    }
  }
  high ans;
  ans.init();
  for (int i = 0;i < n.size();++i) {
    int cur = n[i] - '0';
    ans.mul(d[cur]);
  }
  ans.print();
}

第一次写markdown,以后都会是markdown

posted @ 2021-02-08 22:27  周昂没有周昂  阅读(183)  评论(0)    收藏  举报