这种选做题的设置真是太人性化了,为陈老师点赞
B - 简单枚举
题目描述
参考代码
#include<iostream>
using namespace std;
bool isLegal(int a, int b) {
int used[10] = {0};
for (int i = 0; i < 5; i++) {
used[a % 10]++;
a /= 10;
used[b % 10]++;
b /= 10;
}
for (int i = 0; i < 10; i++) {
if (used[i] != 1)
return false;
}
return true;
}
int main() {
int n;
int ncase = 0;
while (cin >> n && n) {
if (ncase++)
cout << endl;
int fghij = 1234; // start from the smallest 5-digit number
bool legal = false;
while (n * fghij <= 98765) {
if (isLegal(n * fghij, fghij)) {
legal = true;
printf("%05d / %05d = %d\n", n * fghij, fghij, n);
}
fghij++;
}
if (!legal)
printf("There are no solutions for %d.\n", n);
}
return 0;
}
代码讲解
原本是要把十位数都枚举一遍,复杂度是10^10,现在只枚举后五位,前五位用后五位和给定的n相乘得出,复杂度瞬间降到10^5.
D - Ignatius and the Princess II
题目描述
参考代码
#include<iostream>
#include<algorithm>
using namespace std;
int num[1010];
int main(){
int n,m;
while(cin>>n>>m){
for(int i=1;i<=n;i++)
num[i]=i;
int tmp=1;
do{
if(tmp==m)
break;
tmp++;
}while(next_permutation(num,num+n+1));
for(int i=1;i<n;i++)
cout<<num[i]<<" ";
cout<<num[n]<<endl;
}
}
代码讲解
核心就是要理解next_permutation()的使用
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {1, 2, 3};
do {
for(int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
} while(std::next_permutation(vec.begin(), vec.end()));
return 0;
}
具体解释如下:
- 第一个参数:表示序列的起始位置。通常,这是指向容器(如
vector
或数组)中第一个元素的迭代器。 - 第二个参数:表示序列的结束位置。对于容器(如
vector
),这通常是end()
迭代器。对于数组,这是指向数组最后一个元素之后的位置的指针。
这两个参数定义了一个半开区间 [begin, end)
,即包括起始位置但不包括结束位置。std::next_permutation
会在这个区间内生成下一个排列。
F - Joseph
题目描述
参考代码
#include<iostream>
using namespace std;
int a[14]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881};
int main(){
int k;
while(cin>>k&&k){
cout<<a[k]<<"\n";
}
}
代码讲解
打表!因为k的范围只有1-13,所以先暴力把13个算出来再乘起来就可以。