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