分析
-
通过率感人的题目
-
考点
- 搜索
- 剪枝
- 排序
- 质数
- 最大公约数
-
思路
- 首先看到数值的位数最高达9位,所以暴力枚举肯定是会超时的,然后看到数据范围比较小,可以直接枚举加剪枝。
- 我一直卡在第三个测试点,这里是需要对结果进行排序。后来我直接用set存,然后输出就对了。
-
注意:
- 这道题还可以考查一些东西,虽然我想到了,但是题目没有考,反而考了一个排序,没有仔细读题,害我找了半天。
- 如果位数最大包含10位,这里可以考查整数溢出。
- 正整数的首位不能为0,比如010,虽然占了三位,但是数值本质是两位,要小心。
- 这道题还可以考查一些东西,虽然我想到了,但是题目没有考,反而考了一个排序,没有仔细读题,害我找了半天。
-
详细讲解
- 见B站视频:我不是匠人。
AC代码
#include <iostream>
#include <cmath>
#include <unordered_set>
#include <set>
using namespace std;
bool tag;
unordered_set<int> st;
using LL = long long;
int gcd(int a, int b) {
return b==0?a:gcd(b, a%b);
}
bool isPrime(int x){
if(x <= 1) return false;
int sq = sqrt(x);
for(int i = 2; i <= sq; i++) {
if(x % i == 0) return false;
}
return true;
}
set<pair<int,LL>> res;
void dfs(int u, int K, int m, int sum, LL A) {
if(u > K) return;
if(sum + (K-u) > m) return;
if(sum + (K-u)*9 < m) return;
if(u == K) {
if(sum == m) {
LL val = A + 1;
int n = 0;
do{
n += val%10;
val /= 10;
}while(val);
if(st.count(n)){
res.insert({n, A});
tag = true;
}
}
return;
}
for(int i = 0; i <= 9; i++) {
if(!u && !i) continue;
dfs(u+1, K, m, sum + i, A*10ll+i);
}
}
int main() {
int N;
cin >> N;
for(int i = 1; i <= N; i++) {
printf("Case %d\n", i);
tag = false;
int K, m;
cin>>K>>m;
st.clear();
for(int i = 1; i <= 90; i++) {
auto t = gcd(i, m);
if(t > 2 && isPrime(t)) {
st.insert(i);
}
}
res.clear();
dfs(0, K, m, 0, 0);
if(!tag) puts("No Solution");
else{
for(auto x: res) {
printf("%d %lld\n", x.first, x.second);
}
}
}
return 0;
}
视频版
/*
已知: A 和 m
1. A + 1的各位数之和 n
暴力解法
每一位上的数字
----
1 2 3 4
K
0~9
注意: 数字的首位不能为0
1. dfs去枚举每一个位上的数值
2. 剪枝 K = 9 6 3 9+27 < m = 60
3. tag标记有解的情况
4. 要按照顺序输出 n, A递增
5. 求素数
6. 求最大公约数
7. 10位,int会溢出
*/
#include <iostream>
#include <cmath>
#include <unordered_set>
#include <set>
using namespace std;
bool tag;
unordered_set<int> st;
int gcd(int a, int b) {
return b==0?a:gcd(b, a%b);
}
bool isPrime(int x){
if(x <= 1) return false;
int sq = sqrt(x);
for(int i = 2; i <= sq; i++) {
if(x % i == 0) return false;
}
return true;
}
set<pair<int, int>> res;
void dfs(int u, int K, int m, int sum, int A) {
if(u > K) return;
if(sum + (K-u)*9 < m) return;
if(u == K){
if(sum == m) {
int B = A + 1;
int n = 0;
do{
n += B%10;
B /= 10;
}while(B);
if(st.count(n)) {
tag = true;
res.insert({n, A});
}
}
return;
}
for(int i = 0; i <= 9; i++) {
if(!u && !i) continue;
dfs(u+1, K, m, sum+i, A*10+i);
}
}
int main() {
int N;
cin >> N;
for(int i = 1; i <= N; i++) {
printf("Case %d\n", i);
int K, m;
cin >> K >> m;
tag = false;
//预处理m, n
st.clear();
res.clear();
for(int n = 1; n <= 90; n ++) {
auto t = gcd(n, m);
if(t > 2 && isPrime(t)){
st.insert(n);
}
}
// 深度搜索
dfs(0, K, m, 0, 0);
if(!tag) puts("No Solution");
else{
for(const auto&x: res) {
printf("%d %d\n", x.first, x.second);
}
}
}
return 0;
}