洛谷训练新手村之“过程函数与递归”题解

P1028 数的计算

题目链接:https://www.luogu.com.cn/problem/P1028
题目大意:以递归的方式输出题目描述中的数据方案数。
解题思路:
因为是方案数,所以只需要开一个计数器统计一下总共有多少方案即可。我们令 f(n) 返回数为 n 的时候的方案数,不难得出: \(f(n) = 1 + \sum_{i=1}^{ \lfloor \frac{n}2 \rfloor } f(i)\)
但是需要注意一个细节,我们需要用到 备忘录 (或者称为 记忆化搜索 )的思想,即,如果我已经统计过了 \(f(n)\) ,那么我就在统计的同时将结果记录到一个输出 \(cnt[n]\) 中,下次我直接返回 \(cnt[n]\) 即可。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int a, cnt[1001];
int f(int num) {
    if (cnt[num]) return cnt[num];
    cnt[num] = 1;
    for (int i = 1; i <= num/2; i ++) cnt[num] += f(i);
    return cnt[num];
}
int main() {
    cin >> a;
    cout << f(a) << endl;
    return 0;
}

P1036 选数

题目链接:https://www.luogu.com.cn/problem/P1036
题目大意:找出n个数中选k个数,并且这k个数的和是素数的方案数。
解题思路: 深度优先搜索 遍历一下即可。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
bool isp(int a) {
    if (a < 2) return false;
    for (int i = 2; i <= a/i; i ++) if (a%i == 0) return false;
    return true;
}
int n, k, a[22], cnt;
void dfs(int id, int m, int sum) {
    if (m == k) {
        if (isp(sum))
            cnt ++;
        return;
    }
    if (id > n) return;
    dfs(id+1, m, sum);
    dfs(id+1, m+1, sum+a[id]);
}
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    dfs(1, 0, 0);
    cout << cnt << endl;
    return 0;
}

P1149 火柴棒等式

题目链接:https://www.luogu.com.cn/problem/P1149
题目大意:给你 n 根火柴,问拿这 n 根火柴能够拼出多少个不同的等式。
解题思路:开一个数组存放每个数对应的火柴棒数量,然后枚举每一个加数和被加数,看看是不是等式刚好使用了 n 根火柴棒(我自己测了一下加数和被加数最大是712,所以我就枚举到了712)。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int refn[10] = { 6,2,5,5,4,5,6,3,7,6 };
int get_num(int num) {
    if (!num) return 6;
    int ans = 0;
    while (num) {
        ans += refn[num%10];
        num /= 10;
    }
    return ans;
}
int n, ans = 0;
int main() {
    cin >> n;
    for (int i = 0; i < 712; i ++) {
        for (int j = 0; j < 712; j ++) {
            if (get_num(i) + get_num(j) + get_num(i+j)+4 == n) {
                ans ++;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

P1217 [USACO1.5]回文质数 Prime Palindromes

题目链接:https://www.luogu.com.cn/problem/P1217
题目大意:找到区间 \([a,b]\) 范围内的所有会问质数。
解题思路:
首先考虑枚举区间 \([a,b]\) 内的每一个数,判断是否是回文,是否是质数,但是这样超时了。
然后考虑优化,只判断奇数,结果还是超时。
然后考虑有数组存数的每一位(最高 8 位数)以此直接枚举所有的回文数,然后判断是不是素数并且在 \([a,b]\) 范围内。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int t[10], a, b;

int pow10(int a) {  // 求10的a次方
    int s = 1;
    while (a --) s *= 10;
    return s;
}
int get_num(int pre, int len) { // 返回前半部分是pre的位数是len的回文数字
    int a = 1, b = 0, c = pre;
    len = len/2;
    for (int i = 0; i < len; i ++) a *= 10;
    while (c) {
        b = b * 10 + c % 10;
        c /= 10;
    }
    return pre * a + b % a;
}
bool isp(int a) {
    if (a < 2) return false;
    for (int i = 2; i <= a/i; i ++) if (a % i == 0) return false;
    return true;
}
int main() {
    cin >> a >> b;
    for (int len = 1; len <= 8; len ++) {   // 枚举数字位数
        int maxv = pow10((len+1)/2);
        for (int i = maxv/10; i < maxv; i ++) {
            int num = get_num(i, len);
            if (num < a) continue;
            if (num > b) break;
            if (isp(num))
                cout << num << endl;
        }
    }
    return 0;
}
posted @ 2019-11-25 12:52  quanjun  阅读(338)  评论(0编辑  收藏  举报