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; }