首页 > 其他分享 >【题解】 [NOIP 2002 普及组] 产生数

【题解】 [NOIP 2002 普及组] 产生数

时间:2024-08-13 20:40:15浏览次数:12  
标签:闭包 15 NOIP int 题解 2002 变换 Floyd 一位数

题目描述

题目大意

给定 \(k\) 个规则,规则为“使一位数可变换成另一个一位数”。求整数 \(n\) 根据规则经过若干次(可以为0次或多次)变化,能生成的整数个数。

思路

该题主要考察: Floyd传递闭包,高精度乘法。

显而易见,规则具有传递性。举个例子,1可变换成2,2可变换成3,则1可变换成3。
当然,自己也可以变换成自己。
所以,首先用Floyd传递闭包传递出转换关系。
接着,统计出每个一位数可以变换成的一位数的数量
最后,运用乘法原理,将整数 \(n\) 每一位的变换可能数相乘即可。

但是,需要注意的有2点:

  1. \(n < 10^{30}\),所以需要用字符串储存
  2. 答案可能过大,需要用高精度乘法进行运算。

代码

#include <bits/stdc++.h>
using namespace std;

string n; // 用字符串储存 n 
int k, cnt[15]; // cnt[i] 储存 一位数i的变换可能数 
bool a[15][15]; // a[i][j] 表示 i能否变换成j 

int ans[1005]; // 记录答案(高精度) 

int main()
{
    cin >> n >> k;
    while (k -- )
    {
        int u, v; cin >> u >> v;
        a[u][v] = 1;
    }

    // Floyd传递闭包
    for (int k = 1; k <= 9; k ++ )
    for (int u = 0; u <= 9; u ++ )
            for (int v = 1; v <= 9; v ++ )
                if (a[u][k] && a[k][v]) a[u][v] = 1;

    // 统计 变换可能数
    for (int u = 0; u <= 9; u ++ )
    {
        a[u][u] = 1; // 自己可以变换成自己
        for (int v = 0; v <= 9; v ++ )	
            if (a[u][v]) cnt[u] ++ ;
    }

    int jw = 0; // 进位变量 
    ans[0] = 1; // 答案初始值为1,即不进行变换 
    for (int i = 0; n[i]; i ++ )
    {
        jw = 0; // 每次重置进位变量 
        int num = cnt[n[i] - '0']; // 整数n第i位对应的变换可能数

        // 高精度乘法,将答案乘以 变换可能数
        for (int j = 0; j < 500; j ++ )
        {
            ans[j] = ans[j] * num + jw;
            jw = ans[j] / 10;
            ans[j] %= 10;
        }
    }

    // 处理前导0
    int i = 500;
    while (ans[i] == 0) i -- ;

    // 倒序输出
    for ( ; i >= 0; i -- ) cout << ans[i];
    cout << '\n';

    return 0;
}

标签:闭包,15,NOIP,int,题解,2002,变换,Floyd,一位数
From: https://www.cnblogs.com/T-hong/p/18357576

相关文章

  • P8997 题解
    P8997思路按题意模拟,用栈建出二叉树,叶子节点是要填的值,非叶子是运算符。判断一个叶子能贡献能填哪些数并最终成为答案,即dp计算要使该叶子的值\(ans\)成为答案最少要填\(num0\)个\(<=ans\)和\(num1\)个\(>ans\)的数。发现dp只与\(\leans\)和\(>ans\)的数的个......
  • P8996 题解
    P8996思路当有\(a_i<a_j\)时,先放\(a_i\),再放\(i\)之后连续的\(a_k<a_i\)。设\(i\)后第一个比\(a_i\)大的位置是\(nxt_i\),对于一个前缀最大值位置\(i\),合并后\([i,nxt_i)\)的顺序不变且依然连续。让前缀最大值\(a_l\)代表整个区间,可以看做合并是将两个序列的前缀......
  • arc182c 题解
    arc182c思路有\(6\)个小于\(14\)的质数,设这\(6\)个质数的指数分别为\(x_1,\dotsb,x_6\)。\(ans=\sum(\prod_{i=1}^d(x_i+1))\)。状压这\(6\)个数,维护\(val_s=\prod_{i=1}^6(x_i\times[s二进制第i位为1]+[s二进制第i位为0])\)。当加入一个数时,某些\(x_i\)会加......
  • CF1294F 题解
    Part.0闲话更好的观看体验目前题解区里大多数巨佬都是采用的树形dp和暴力等方法,看见没有我这种做法,欢迎指出做法问题或hack代码。Part.1题意给定一棵树,选\(3\)个点\(a,b,c\),求\(a\)到\(b\)的路径与\(a\)到\(c\)的路径与\(b\)到\(c\)的路径上一共有多少......
  • 新坑:信息学奥赛一本通题解(3001~3005)
    前言Hello,大家好我是文宇,开个新坑,是关于信息学奥赛一本通的坑,就是信奥赛题解.(这里指编程启蒙的题库)因为作者的洛谷还在写,只是信奥赛的题写的比较多,所以先做信奥赛的.信奥赛的网址是信息学奥赛一本通-编程启蒙(C++版)在线评测系统(挖坑:作者以后可能还会有信奥赛本体......
  • 生活在hzoi上 题解
    生活在hzoi上题解考虑有两棵树怎么做,显然是\(y^{n-k}=y^{n-\left\vertE_1\capE_2\right\vert}\)其中\(E_1\)和\(E_2\)是两棵树的边集发现上边那个\(k\)是两棵树边集交构成的图的连通块个数\(\left\vertE_1\capE_2\right\vert\)就是两棵树交的连通块数量......
  • 记一次NoClassDeffoundEror问题解决过程
    背景:在对某台计算服务器进行代码修改后,发现es查询报错,抛出异常如下: 思路: 1.jar包冲突   查询了对应jar的pom文件,发现只有一个es的版本jar包,不存在冲突,百思不得其解。2.本地环境问题   清理idea的缓存,发行问题仍然存在最后翻阅资料,打了断点追踪异常抛出的地方,......
  • ARC182 题解
    A-ChmaxRush!发现一个数能向哪边覆盖只由再他之后操作且\(v\)比他大的操作决定。所以扫一遍确定方向之后乘起来就好。B-|{floor(A_i/2^k)}|首先不难发现\(<2_{k-1}\)的元素是无用的,因为它们会由\(\ge2^{k-1}\)的元素除以2的幂得到。先想上界。对于\(0\l......
  • ARC182B |{floor(A_i/2^k)}| 题解
    ARC182B|{floor(A_i/2^k)}|题解题目大意定义一个长度为\(N\)的序列\(A\)的分数为能被表示成\(\lfloor{A_i\over2^k}\rfloor\)的数的个数,其中\(i=1,2,\dots,N\),\(k\)为任意自然数。给定\(N,K\),求长度为\(N\)且元素大小都在\(2^K-1\)内的所有序列的分数的最大值......
  • 【题解】 [USACO 2007 FEB] Cow Party S
    题目描述题目大意给定一个有向图,以及一个顶点。求其他所有点到给定点,再从给定点回到各自起始点的最短路中的最大值。思路本题主要考查:对单源最短路算法的熟练运用。最短路总共分为2段:其他所有点到给定点、给定点回到各自起始点。首先求第一段:可以在原图的基础上建一个反向图......