• 2001年NOIP普及组复赛题解


    题目涉及算法:

    • 数的计算:动态规划;
    • 最大公约数和最小公倍数问题:质因数分解;
    • 求先序排列:递归;
    • 装箱问题:动态规划(纯0-1背包问题)

    数的计算

    题目链接:https://www.luogu.org/problem/P1028
    这道题目可以用动态规划进行求解。
    我们令 (f[i]) 表示自然数为 (i) 能够生成的数的个数,则:
    (f[i] = 1 + sum_{j=1}^{n/2} f[j])
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1010;
    int n, f[maxn];
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i ++) {
            f[i] = 1;
            for (int j = 1; j <= i/2; j ++)
                f[i] += f[j];
        }
        cout << f[n] << endl;
        return 0;
    }
    

    最大公约数和最小公倍数问题

    题目链接:https://www.luogu.org/problem/P1029
    这道题目虽然名为“最大公约数和最小公倍数问题”,但其实是一道 质因数分解 的问题。
    首先,如果P不能整除Q,那么答案肯定为 (0) ,直接输出 (0) 即可。
    其次,我们令 (n = Q/P) ,然后对 (n) 进行质因数分解,假设对 (n) 进行质因数分解的表达式为:
    (n = a_1^{b_1} imes a_2^{b_2} imes dots imes a_m^{b_m})
    那么我们知道,对于其中的任意一个 (a_i) ,它要么归到 (x0) ,要么归到 (y0) ,不可能有 (1)(a_i) 归到 (x0) ,而另一个 (a_i) 归到 (y0) (因为这个时候他们的最大公约数就变成了 (x0 imes a_i)) ,所以对于这 (m)(a_i) ,他们要么都归到 (x0) ,要么都归到 (y0) ,所以总的方案数就是 (2^m)
    实现代码如下(代码中我用 (cnt) 来表示不同的质因数个数):

    #include <bits/stdc++.h>
    using namespace std;
    int n, m, P, Q, cnt;
    long long ans = 1;
    int main() {
        cin >> P >> Q;
        if (Q % P) {
            puts("0");
            return 0;
        }
        n = Q / P;
        m = sqrt(n);
        for (int i = 2; i <= m; i ++) {
            if (n % i == 0) {
                cnt ++;
                while (n % i == 0) n /= i;
            }
        }
        if (n > 1) cnt ++;
        cout << ( 1LL << cnt ) << endl;
        return 0;
    }
    

    求先序排列

    题目链接:https://www.luogu.org/problem/P1030
    这道题目可以用“递归”进行求解。
    首先,后续序列的最后一个元素肯定是当前子树的根节点。
    我们可以在中序序列里面找到根节点的位置,然后中序序列例根节点左边的子串对应该根节点的左子树,右边的子串对应根节点的右子树。我们递归地进行遍历就可以还原出这棵树。
    同时,我们在递归的时候其实也可以直接输出这棵树的先序遍历结果。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    char zx[10], hx[10];    // zx:中序序列;hx:后序序列
    // [L1,R1]对应中序序列的区间范围;
    // [L2,R2]对应后序序列的区间范围
    void dfs(int L1, int R1, int L2, int R2) {
        if (L1 >= R1) {
            if (L1 == R1) putchar(zx[L1]);
            return;
        }
        int i;
        for (i = L1; i <= R1 && zx[i] != hx[R2]; i ++);
        putchar(zx[i]);
        int l_len = i - L1, r_len = R1 - i;
        dfs(L1, i-1, L2, L2+l_len-1);
        dfs(i+1, R1, R2-r_len, R2-1);
    }
    int main() {
        cin >> zx >> hx;
        int len = strlen(zx);
        dfs(0, len-1, 0, len-1);
        return 0;
    }
    

    装箱问题

    题目链接:https://www.luogu.org/problem/P1049
    这道题目是一道纯0-1背包问题。
    对于第i件物品,我们令它的体积等于价值,套0-1背包模板能够得到能装进箱子的最大价值。以箱子总体积减去总价值就是箱子的最小的剩余空间。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 20020;
    int n, V, c, f[maxn];
    int main() {
        cin >> V >> n;
        while (n --) {
            cin >> c;
            for (int i = V; i >= c; i --)
                f[i] = max(f[i], f[i-c] + c);
        }
        cout << V - f[V] << endl;
        return 0;
    }
    

    作者:zifeiy

  • 相关阅读:
    20155206 2017-2018-1 《信息安全系统设计基础》第3周学习总结
    20155206 第三周随堂测试补交
    20155206 2017-2018-1 《信息安全系统设计基础》第1周学习总结
    20155206 实验五 网络编程与安全
    20155206 2016-2017-2《Java程序设计》课程总结
    20155206 《Java程序设计》实验四实验报告
    第十二周课堂练习
    J-5 Java语言基础
    C-2 方法重载,比较大小
    C-1 九九乘法表
  • 原文地址:https://www.cnblogs.com/codedecision/p/11712219.html
Copyright © 2020-2023  润新知