首页 > 其他分享 >CSP历年复赛题-P1037 [NOIP2002 普及组] 产生数

CSP历年复赛题-P1037 [NOIP2002 普及组] 产生数

时间:2024-05-22 11:10:40浏览次数:22  
标签:10 string NOIP2002 int P1037 dfs ++ vector CSP

原题链接:https://www.luogu.com.cn/problem/P1037

题意解读:一个长整数,有若干数字替换规则,计算可以转换成多少种不同的整数。

解题思路:

看题之后,第一感觉,是用DFS:

1、用字符串存储整数

2、用领接表存储数字替换规则,因为一个数字可以替换成多个其他数字

3、在dfs中,枚举字符串每个数字,再枚举规则中每一个可能替换的数字,进行一次替换,继续dfs

隐隐感到不安:30位的整数数量已超过long long,估计要高精度;dfs中对数字判重要借助map,大量的string和dfs可能导致超时、超空间。

不管三七二十一,先写出代码,验证正确性,拿到部分分再说!

40分代码:

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

vector<int> g[10];
int ans;
unordered_map<string, int> h;

void dfs(string s)
{
    if(h[s]) return;
    ans++;
    h[s] = 1;
    for(int i = 0; i < s.size(); i++)
    {
        for(int j = 0; j < g[s[i] - '0'].size(); j++)
        {
            string tmp(s);
            tmp[i] = g[s[i] - '0'][j] + '0';
            dfs(tmp);
        }
    }
}

int main()
{
    string s;
    int k;
    cin >> s >> k;
    int a, b;
    for(int i = 1; i <= k; i++)
    {
        cin >> a >> b;
        g[a].push_back(b); //加入a->b的规则
    }
    dfs(s);
    cout << ans;

    return 0;
}

进一步思考,对于整数的每一个数字,可以替换成不同的数,例如样例:

234 2
2 5
3 6

对于整数234的每一位,

2:可以选2、5,2种选法

3:可以选3、6,2种选法

4:只能选4,1种选法

根据乘法原理,234一共可以生成2 * 2 * 1 = 4种不同的数

到这里,应该能想到,此题的正解是通过排列组合的乘法原理,统计出每一位一共有多少种选法,相乘即可(由于数据量大,需要高精度*低精度)

现在,问题关键在于如何统计每一个数可以替换成多少个不同的数?

映射规则不仅可以是2 5,3 6,还可以有5 1,1 7等等,因此非常类似于图的遍历,用领接表存储后,从0~9每个数字开始,进行DFS遍历,遍历到的每一个不同的数字个数就是起始数字可以替换的数的个数。

ok,下面暂时不考虑高精度问题,实现代码:

60分代码:

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

vector<int> g[10];
int r[10]; //0~9可以替换的数的个数
bool h[10]; //hash,标记数是否已经存在
int cnt;
int ans = 1;

//图的遍历,统计从起点能到达的点的个数
void dfs(int i)
{
    if(!h[i]) cnt++;
    h[i] = 1;
    for(int v : g[i])
    {
        if(!h[v]) dfs(v);
    }
}

int main()
{
    string s;
    int k;
    cin >> s >> k;
    int a, b;
    for(int i = 1; i <= k; i++)
    {
        cin >> a >> b;
        g[a].push_back(b); //加入a->b的规则
    }
   
    for(int i = 0; i <= 9; i++)
    {
        memset(h, 0, sizeof(h)); //清0
        cnt = 0; //清0
        dfs(i);
        r[i] = cnt; //保存i可以替换的数的个数
    }
    
    for(int i = 0; i < s.size(); i++)
    {
        ans *= r[s[i] - '0'];
    }
    cout << ans;
    
    return 0;
}

到这里,离AC又进了一步,保持耐心!下面将计算ans *= r[s[i] - '0']的代码修改为高精度乘法~

100分代码:

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

vector<int> g[10];
int r[10]; //0~9可以替换的数的个数
bool h[10]; //hash,标记数是否已经存在
int cnt;
vector<int> ans(1, 1); //高精度的1

//图的遍历,统计从起点能到达的点的个数
void dfs(int i)
{
    if(!h[i]) cnt++;
    h[i] = 1;
    for(int v : g[i])
    {
        if(!h[v]) dfs(v);
    }
}

//高精度 * 低精度
vector<int> mul(vector<int> a, int b)
{
    vector<int> res;
    int r = 0; //进位
    for(int i = 0; i < a.size(); i++)
    {
        r += a[i] * b;
        res.push_back(r % 10);
        r /= 10;
    }
    while(r)
    {
        res.push_back(r % 10);
        r /= 10;
    }
    return res;
}

int main()
{
    string s;
    int k;
    cin >> s >> k;
    int a, b;
    for(int i = 1; i <= k; i++)
    {
        cin >> a >> b;
        g[a].push_back(b); //加入a->b的规则
    }
   
    for(int i = 0; i <= 9; i++)
    {
        memset(h, 0, sizeof(h)); //清0
        cnt = 0; //清0
        dfs(i);
        r[i] = cnt; //保存i可以替换的数的个数
    }
    
    for(int i = 0; i < s.size(); i++)
    {
        ans = mul(ans, r[s[i] - '0']);
    }
    //高精度,倒序输出
    for(int i = ans.size() - 1; i >= 0; i--)
        cout << ans[i];

    return 0;
}

 

标签:10,string,NOIP2002,int,P1037,dfs,++,vector,CSP
From: https://www.cnblogs.com/jcwy/p/18205782

相关文章

  • CSP历年复赛题-P1002 [NOIP2002 普及组] 过河卒
    原题链接:https://www.luogu.com.cn/problem/P1002题意解读:从A(0,0)点走到B(n,m)点,只能向右或者向下,C点以及其控制点不能走。解题思路:根据题意,此题要么递归(DFS),要么递推(动态规划)先分析数据规模,最大从起点到终点要走40步,每个步有2种走法,一共240种路径,DFS会超时,且方案数必须用longlong......
  • CSP历年复赛题-P1042 [NOIP2003 普及组] 乒乓球
    原题链接:https://www.luogu.com.cn/problem/P1042题意解读:分别针对11分制和21分制,输出每局比分。只需要判断一局的结束条件:得分高者如果达到11或者21,且比分间隔大于等于2分,则表示一局结束,可开始下一局,用模拟法即可解决。100分代码:#include<bits/stdc++.h>usingnamespaces......
  • [CSP-S 2023] 种树
      #include<bits/stdc++.h>#definelllonglong#definepbpush_back#definemxn100003#definerep(i,a,b)for(inti=a;i<=b;++i)#definerept(i,a,b)for(inti=a;i<b;++i)usingnamespacestd;intn,p[mxn],d[mxn],ct[mxn];lla[mxn],b[mxn],c[m......
  • CSP历年复赛题-P1049 [NOIP2001 普及组] 装箱问题
    原题链接:https://www.luogu.com.cn/problem/P1049题意解读:装尽可能多的物品,使得总体积越大越好,即剩余空间最小,还是一个01背包问题,物品的体积就是其价值。解题思路:01背包模版题,物品体积、价值相同,直接采用一维dp。100分代码:#include<bits/stdc++.h>usingnamespacestd;co......
  • CSP历年复赛题-P1035 [NOIP2002 普及组] 级数求和
    原题链接:https://www.luogu.com.cn/problem/P1035题意解读:根据公式模拟法求解即可。解题思路:枚举i,计算sum,如果sum>k,则输出i100分代码:#include<bits/stdc++.h>usingnamespacestd;intmain(){intk;cin>>k;doublesum=0;inti=0;while(......
  • CSP历年复赛题-P1036 [NOIP2002 普及组] 选数
    原题链接:https://www.luogu.com.cn/problem/P1036题意解读:题目即要在n个数中,枚举出所有的子集,当子集中数字个数刚好为k时,求和,判断是否是素数。解题思路:方法一:二进制法通过二进制法,可以枚举一个集合中所有元素“选”或者“不选”的情况,用二进制1表示选该元素,二进制0表示不选。......
  • CSP历年复赛题-P1030 [NOIP2001 普及组] 求先序排列
    原题链接:https://www.luogu.com.cn/problem/P1030题意解读:已知中序、后序,求先序。解题思路:与洛谷题单指南-二叉树-P1827[USACO3.4]美国血统AmericanHeritage非常类似,不在介绍过程,直接给出代码。100分代码:#include<bits/stdc++.h>usingnamespacestd;stringin,post......
  • CSP历年复赛题-P1023 [NOIP2000 普及组] 税收与补贴问题
    原题链接:https://www.luogu.com.cn/problem/P1023题意解读:给定商品单价和对应销量表,计算使得采用预期价格销售得到最大利润时的最小补贴或者税收。解题思路:1、样例模拟31281303012031110-1-115政府预期价格:31商品成本:28,按成本价售卖销量:130商品单价:30,对应销量:120......
  • CSP历年复赛题-P1028 [NOIP2001 普及组] 数的计算
    原题链接:https://www.luogu.com.cn/problem/P1028题意解读:给定n,构造数列,可以用递归或者递推。解题思路:1、递归定义count(n)返回数列的个数  n==1时,count(n)=1  n!=1时,count(n)=1+count(1)+count(2)+...+count(n/2)注意,递归会导致大量重复计算,需要用一个hash......
  • CSP历年复赛题-P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
    原题链接:https://www.luogu.com.cn/problem/P1029题意解读:已知x,y,求有多少对p、q,使得p、q的最大公约数为x,最小公倍数为y。解题思路:枚举法即可。枚举的对象:枚举p,且p必须是x的倍数,还有p<=yq的计算:q=x*y/p,q要存在,必须x*y%p==0,且gcd(p,q)==x100分代码:#include......