P1037 [NOIP 2002 普及组] 产生数

P1037 [NOIP 2002 普及组] 产生数

题目描述

给出一个整数 nnn 和 kkk 个变换规则。

规则:

  • 一位数可变换成另一个一位数。
  • 规则的右部不能为零。

例如:n=234,k=2n=234,k=2n=234,k=2。有以下两个规则:

  • 2⟶52\longrightarrow 52⟶5。
  • 3⟶63\longrightarrow 63⟶6。

上面的整数 234234234 经过变换后可能产生出的整数为(包括原数):

  • 234234234。
  • 534534534。
  • 264264264。
  • 564564564。

共 444 种不同的产生数。

现在给出一个整数 nnn 和 kkk 个规则。求出经过任意次的变换(000 次或多次),能产生出多少个不同整数。

仅要求输出个数。

输入格式

第一行两个整数 n,kn,kn,k,含义如题面所示。

接下来 kkk 行,每行两个整数 xi,yix_i,y_ixi,yi,表示每条规则。

输出格式

共一行,输出能生成的数字个数。

输入输出样例 #1

输入 #1

复制代码
234 2
2 5
3 6

输出 #1

复制代码
4

说明/提示

对于 100%100\%100% 数据,满足 n<1030n \lt 10^{30}n<1030,k≤15k \le 15k≤15。

【题目来源】

NOIP 2002 普及组第三题

对于这题,我们需要考虑每一个数字经过有限次变换可以有多少可能。即其路径上经过了多少个不同的结点。使用floyd-warshall解决这个传递闭包问题。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

vector<int> mul(const vector<int>& num, int m) {
    if (m == 0) {
        return {0};
    }
    vector<int> result;
    int carry = 0;
    for (int digit : num) {
        int product = digit * m + carry;
        result.push_back(product % 10);
        carry = product / 10;
    }
    while (carry > 0) {
        result.push_back(carry % 10);
        carry /= 10;
    }
    return result;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    string n_str;
    int k;
    cin >> n_str >> k;
    bool g[10][10] = {false};
    for (int i = 0; i < 10; ++i) {
        g[i][i] = true;
    }
    for (int i = 0; i < k; ++i) {
        int u, v;
        cin >> u >> v;
        g[u][v] = true;
    }
    for (int kk = 0; kk < 10; ++kk) {
        for (int i = 0; i < 10; ++i) {
            for (int j = 0; j < 10; ++j) {
                if (g[i][kk] && g[kk][j]) {
                    g[i][j] = true;
                }
            }
        }
    }
    int choices[10] = {0};
    for (int i = 0; i < 10; ++i) {
        for (int j = 0; j < 10; ++j) {
            if (g[i][j]) {
                choices[i]++;
            }
        }
    }
    vector<int> num = {1};
    for (char c : n_str) {
        int digit = c - '0';
        num = mul(num, choices[digit]);
    }
    for (int i = num.size() - 1; i >= 0; --i) {
        cout << num[i];
    }
    cout << endl;
    return 0;
}