枚举,故名思意,是一种把所有情况都列举出来,然后在所有情况中找到需要的答案,看似简单但是也需要加以思考
1、找出质数
如果一个数不能被自己和1以外的数字整除,那这个数就是质数。
找出1~ n中的所有质数,两个数之间用括号隔开
10
≤
n
≤
100000
10 \le n\le 100000
10≤n≤100000.
输入样例 #1
15
输出样例 #1
2 3 5 7 11 13
这个题非常简单,我们只需要从一开始枚举每一个数字,依次判断这个数是不是质数,如果是的话就把他输出即可。
answer:
#include<bits/stdc++.h>
using namespace std;
bool func(int n){
if(n == 1)return false;
for(int i = 2; i * i<= n; i++){
if(n % i == 0)return false;
}
return true;
}
int main(){
int n; cin >> n;
for(int i = 1; i <= n; i++){
if(func(i)){
cout << i << " ";
}
}
return 0;
}
2、漆房
包租公A有一条很长的走廊,走廊上并排着很多房间,每个房间的住户都把自己门口的一块地涂成了自己喜欢的颜色,每种颜色用一个整数n来表示(1≤n≤60)。现在A想用一种颜色把整条走廊给刷成一种颜色,A每天只能刷完k间房的门口,请你输出A至少几天才能让走廊统一色号。
输入格式
一个整数n,表示走廊长度,输入一个整数k,表示一天能刷多长。
随后输入n个整数,每个表示每个房间门口的颜色。
输出格式
一个整数,表示最少使用多少天。
输入样例 #1
6 2
1 1 1 2 2 1
输出样例 #1
1
解释
如果全部用1颜色刷的话,一天就能把2-2段给覆盖完,如果用2颜色的话,则需要三天,所以输出1.
由于数据量较小,我们可以直接根据题意来枚举所有情况。
#include<bits/stdc++.h>
using namespace std;
int room[1000];
int main(){
int n, k;
cin >> n >> k;
for(int i = 1; i <= n; i++){
cin >> room[i];
}
int minn = 99999;
for(int i = 1; i <= 60; i++){
//枚举所有颜色
if(minn == 0)break;
int cnt = 0;
for(int j = 1; j <= n; j++){
if(room[j] != i){
//如果颜色不一样就开始刷,即跳过这部分的走廊
cnt++;
j += k - 1;
//因为结束后for循环会给j再加1,所以只要加上k-1即可
}
}
minn = min(cnt, minn);
}
cout << minn;
return 0;
}
3、最大乘积
输入若干组 n n n个数组成的序列, 你需要找出一段连续的乘积最大的子序列,如果这个最大的序列的乘积S不是正数,则输出“无解”。 ( 1 ≤ n ≤ 18 , − 1 0 9 ≤ S ≤ 1 0 9 ) (1 \le n \le 18, -10^9 \le S \le 10 ^9) (1≤n≤18,−109≤S≤109).
输入样例 #1
3
2 4 -3
5
2 5 -1 2 -1
输出样例 #1
8
20
因为此题n较小,所以可以只枚举始末位置,然后逐个相乘即可,这样的复杂度为
n
3
n^3
n3,如果n较大的话,直接枚举则不可取,所以考虑优化。
还记得前缀和吗?我们在前缀和的基础上进行改良即可得到一个新数组:前缀积。
与前缀和类似,我们现在以a[i]记录数字(从a[1]开始),以pre[i]来记录从a[1]连乘到a[i]的值
则:从a[n] 连城到 a[m] 的值则是pre[m] / pre[n - 1]。特别的,我们需要讲pre[0]初始化为1.
这样的话我们就能只用枚举起始位置,并且不用每次枚举都要连乘一遍。复杂度为 n 2 n^2 n2.
#include<bits/stdc++.h>
using namespace std;
void solve(int n){
long long pre[n + 3];
for(int i = 1; i <= n; i++){
cin >> pre[i];
pre[i] = pre[i - 1] * pre[i];
}
long long maxx = -9999999;
for(int i = 0; i < n; i++){
for(int j = i + 1; j <= n; j++){
maxx = max(pre[j] / pre[i], maxx);
}
}
if(maxx >= 0)cout << maxx << endl;
else cout << "无解" << endl;
}
int main(){
int n;
while(cin >> n){
solve(n);
}
return 0;
}
4、除法
输入任意正整数k,按从小到大的顺序输出所有满足 a b c d e / f g h i j = n abcde/fghij = n abcde/fghij=n的表达式,其中 a a a$j$恰好是$0$ 9 9 9的一个排列,即 a b c d f e g h i j abcdfeghij abcdfeghij是不重复的单个数字(可包含前导零)。 2 ≤ n ≤ 79 2 \le n \le 79 2≤n≤79.
输入样例 #1
62
输出样例 #1
79546 / 01283 = 62
95736 / 01528 = 62
这一题要枚举0~9的全排列然后来配对出 abcde 和 fghij 的所有情况吗?想一下,全排列一共有
10
!
10!
10!种,这个数据量太大了。我们可以通过枚举 fghij,然后用 figij 来 算出 abcde 。然后判断每一位的数字会不会重复,然后在两个数加起来超过十位时终止枚举即可。
to_string 是把数字转化为字符串。我们每次把 fghij 转换成 s1,把 abcde 转化为 s2。然后把两个字符串组合,根据字符串的长度来判断是否要结束枚举,如果加起来的字符长度为9,那可能是缺少前导0,所以我们给他补上一个0。
#include<bits/stdc++.h>
using namespace std;
int func(int n, int m){
string s1 = to_string(n);
string s2 = to_string(m);
s1 = s1 + s2;
if(s1.size() > 10 || s2.size() > 5)return 3;
if(s1.size() < 9)return 1;
if(s1.size() == 9)s1 = s1 + '0';
set<char>s;
for(int i = 0; i < 10; i++){
s.insert(s1[i]);
}
if(s.size() == 10)return 2;
else return 1;
}
int main(){
int n;
cin >> n;
for(int i = 1000; ;i++){// fghij 可以是四位数,并且最小是能是四位数
int j = i * n;
int t = func(i, j);
if(t == 1)continue;
else if(t == 3)break;
else if(t == 2){
printf("%05d / %05d = %d\n",j, i, n);
}
}
return 0;
}
5、分数拆分
输入若干组数字,每组一个正整数k,找出所有的正整数 x > = y . x >= y. x>=y.使得 1 k = 1 x + 1 y . \displaystyle\frac{1}{k} = \displaystyle\frac{1}{x} + \displaystyle\frac{1}{y}. k1=x1+y1.
输出格式
一个数字n,表示满足要求的组数,随后n行,按y从小到大输出每一组
输入样例 #1
2
12
输出样例 #1
2
1 / 2 = 1 / 6 + 1 / 3
1 / 2 = 1 / 4 + 1 / 4
8
1 / 12 = 1 / 156 + 1 / 13
1 / 12 = 1 / 84 + 1 / 14
1 / 12 = 1 / 60 + 1 / 14
1 / 12 = 1 / 48 + 1 / 16
1 / 12 = 1 / 36 + 1 / 18
1 / 12 = 1 / 30 + 1 / 20
1 / 12 = 1 / 28 + 1 / 21
1 / 12 = 1 / 24 + 1 / 24
由于除法的精度损,我们尽量把除法转化成乘法。
由
1
k
=
1
x
+
1
y
→
k
x
+
k
y
=
x
y
即:
x
(
y
−
k
)
=
k
y
由\displaystyle\frac{1}{k} = \displaystyle\frac{1}{x} + \displaystyle\frac{1}{y} → kx + ky = xy\ \ \ \ 即:x(y - k) = ky
由k1=x1+y1→kx+ky=xy 即:x(y−k)=ky
因为 y 可以远小于 x,所以我们应该用 y 去推 x,那什么时候停止推算呢?
因为
x
>
=
y
→
1
x
<
=
1
y
因为x >= y → \displaystyle\frac{1}{x}<=\displaystyle\frac{1}{y}
因为x>=y→x1<=y1
这样的的话,
1
k
=
1
x
+
1
y
→
1
k
−
1
x
=
1
y
这样的的话,\displaystyle\frac{1}{k} = \displaystyle\frac{1}{x} +\displaystyle\frac{1}{y}→\displaystyle\frac{1}{k} - \displaystyle\frac{1}{x} = \displaystyle\frac{1}{y}
这样的的话,k1=x1+y1→k1−x1=y1
即:
1
k
−
1
y
<
=
1
y
,
即:
1
k
<
=
2
1
y
;
即
2
k
>
=
y
即:\displaystyle\frac{1}{k} - \displaystyle\frac{1}{y} <=\displaystyle\frac{1}{y}, 即:\displaystyle\frac{1}{k} <= 2\displaystyle\frac{1}{y}; 即2k >= y
即:k1−y1<=y1,即:k1<=2y1;即2k>=y
这样的话我们只需要把y枚举到2k即可。
因为要先输出组数,再输出每组内容,所以可以使用一个不定长数组来解决。
#include<bits/stdc++.h>
using namespace std;
void solve(int k) {
vector<int>x, y;
for(int i = 1; i <= 2 * k; i++){
if(i <= k)continue; //分母不能为0和复数
if(k * i % (i - k) == 0){
int j = k * i / (i - k);
x.push_back(j);
y.push_back(i);
}
}
cout << x.size() << endl;
for(int i = 0; i < x.size(); i++){
printf("1 / %d = 1 / %d + 1 / %d\n", k, x[i], y[i]);
}
}
int main(){
int k;
while(cin >> k){
solve(k);
}
return 0;
}