2021年12月24日

103 阅读6分钟

1.优秀的拆分

题意

image.png image.png

输入和输出

image.png

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
	10 = 8 + 2 = 2^3 + 2^1 优秀的拆分
	7 = 4 + 2 + 1 = 2^2 + 2^1 + 2^0 不优秀的拆分,因为2^0=1不是2的正整数次幂

	1.定义变量n, m = 2
	2.输入n
	3. 如果n是奇数,就说明最后一定会有2^0,所以输出-1,return 0;
	4. 只要m小于n, 重复做:
			a. 将2累乘并赋值给m
	5. 如果m大于n , 就m除等于2
	6. 只要n不为0, 重复做:
		a. 输出m
		b. 拿n减去m再赋值给自身
		c. 只要m>n, do:
		  c-1. m除等于2
*/

int main() {
	ios::sync_with_stdio(false);
	int n, m = 2;
	cin >> n;
	if(n % 2) {
		cout << -1;
		return 0;
	}
	while(m < n)
		m *= 2;
	if(m > n)
		m /= 2;
	while(n) {
		cout << m << " ";
		n -= m;
		while(m > n)
			m /= 2;
	}
	return 0;
}

2.即约分数

题意

image.png

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
	1/4, 1/8, 7/1 分子和分母的最大公约数是1 => 即约分数
	
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ccef11a2e486412595fe72199db6a330~tplv-k3u1fbpfcp-watermark.image?)
    求1到2020之间有多少个即约分数
    1. 定义最大公约数函数:gcd(int m, int n), 定义计数器cnt = 0
        a. 如果除数等于0,返回被除数  gcd(25,0) => 25
        b. 递归调用自身(n, m % n), 被除数变成原来的除数,除数变成m%n的结果
	2. for i=1 to 2020, 重复做:
			for j=1 to 2020, 重复做:
				a. 如果gcd(i,j)等于1, 就cnt加1
	3. 输出cnt
*/
//最大公约数
int gcd(int m, int n) {
	if(n == 0)
		return m;
	return gcd(n, m % n);
}

int main() {
	ios::sync_with_stdio(false);
	int cnt = 0;
	F(i,1,2021) {
		F(j,1,2021) {
			if(gcd(i,j) == 1)
				cnt++;
		}
	}
	cout << cnt;
	return 0;
}

3.音节判断

题意

image.png

输入输出

image.png

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
	h e ll o
 	h:辅音,e:元音, ll:辅音, o元音 => yes
 	一共四段,每一段都可以由多个字母组成
 	
 	l a n q i a o
 	l:辅音 a:元音  nq:辅音  iao:元音

	1. 定义字符串s, cnt = 0, flag1 = 1(辅音), flag2 = 1(元音)
	2. 输入s
	3. 遍历字符串,重复做:
			a.如果当前字符是辅音,就cnt+1, 辅音关了,把元音开了
			b.如果当前字符是元音,就cnt+1, 元音关了,把辅音开了
	4. 如果cnt等于4个音节,就输出yes,否则,输出no
	
*/


int main() {
	ios::sync_with_stdio(false);
	string s;
	int cnt = 0, flag1 = 1, flag2 = 1;
	getline(cin, s);
	F(i,0,s.size()) {
		if((s[i] != 'a' && s[i] != 'e' && s[i] != 'i' && s[i] != 'o' && s[i] != 'u') && flag1)
		{
			cnt++;
			flag1 = 0;
			flag2 = 1;
		}
		if((s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u') && flag2)
		{
			cnt++;
			flag1 = 1;
			flag2 = 0;
		}
	}
	if(cnt == 4)
		cout << "yes";
	else
		cout << "no";
	return 0;
}

4.机器翻译

题意

image.png

image.png

输入输出

image.png

未ac的代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
 软件先从内存中查找这个单词的中文含义
  如果内存中有,软件就会用它进行翻译
  如果内存中没有,就从外存的词典中查找,然后翻译
  并将该单词和意思放入内存,以便后续的查找和翻译

  内存中有M个单元,每单元只能存放一个单词和词义
  先进先出

  1, 定义变量m(内存单元),n(文章长度),数组a,队列q(模拟内存),cnt=0(查询次数)
  2. 输入m,n
  3. 遍历文章长度,输入a[i]
  4. for i=0 to n-1, 重复做:
		a. 如果内存中没有a[i]的记录且内存未满
			a-1.就将a[i]存到内存中
			a-2. cnt加1
		b. 如果内存中有a[i]的记录,就continue(跳过)
		c. 如果内存中没有a[i]的记录且内存已满
			a-1. 把内存最早存的单词清掉
			a-2. 内存减1
			a-3. 再将a[i]存到内存中
			a-4. 内存加1
			a-5. cnt加1
  5. 输出cnt
*/
const int N = 100860;
int m,n, cnt = 0, nc = 0; //内存单元,文章长度,查询次数
int a[N];
int front=-1, rear=-1; //队头和队尾
int q[N];
void enqueue(int val) {
	//1.检查队列是否为空
	if(front == -1 && rear == -1) {
		front = rear = 0;
		q[rear] = val;
	}
	//2.队列是否已满
	else if((rear + 1) % m == front)
		return;
	else {
		rear = (rear + 1) % m;
		q[rear] = val;
	}
}
void dequeue() {
	//1.当队列为空时
	if(front==-1 && rear == -1)
		return;
	//2.当队列只有一个元素时
	else if(front == rear) {
		front = -1;
		rear = -1;
	}
	//3.队列有多个元素时
	else {
		front = (front + 1) % m;
	}
}
int findX(int x) {
	for(int i = 0; i < N; i++) {
		if(q[i] == x)
			return 1;
	}
	return 0;
}

int main() {
	ios::sync_with_stdio(false);
	cin >> m >> n;
	F(i,0,n) cin >> a[i];
	F(i,0,n) {
		if(findX(a[i])==0 && nc < m) {
			enqueue(a[i]);//放入到内存
			cnt++; //查询次数+1
			nc++; //内存加1
		} else if(findX(a[i])==0 && nc >= m) {
			dequeue(); //从内存中去除记录
			nc--;   //内存减1
			enqueue(a[i]); //放入到内存
			nc++; //内存加1
			cnt++; //查询次数+1
		} else continue;
	}
	cout << cnt;
	return 0;
}

ac代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
int m,n, x, cnt = 0;
vector<int> v;
/*
	1.定义变量m,n,x(输入),cnt=0
	2. 输入m和n
	3. 遍历文章,重复做:
		a. 输入x
		b. 如果内存中没有该单词, 就将该单词存入到内存中,查询次数加1
		c. 如果内存满了,就把最早存入的单词移除
*/
int main() {
	ios::sync_with_stdio(false);
	cin >> m >> n; //输入内存和文章长度
	while(n--) {
		cin >> x;
		if(find(v.begin(), v.end(), x) == v.end()) {
			v.push_back(x);
			++cnt;
		}
		if(v.size() > m)
			v.erase(v.begin());
	}
	cout << cnt << endl;
	return 0;
}

ac代码 队列模拟内存

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
int m,n,cnt = 0,x;
const int N = 1005;
bool inqueue[N]; //是否在队列里
queue<int> q; //用队列来模拟内存
/*
	1.定义变量m,n,x(输入),cnt=0
	2. 输入m和n
	3. 遍历文章,重复做3:
		a. 输入x
		b. 如果内存中没有该单词
			b-1就向外存查找,查询次数加1
			b-2.将该单词存入到内存中
			b-3.标记放入
		c. 如果内存满了
			c-1.将内存最开始的位置标记未放入
			c-2.就把最早存入的单词移除
*/
int main() {
	ios::sync_with_stdio(false);
	cin >> m >> n; //输入内存和文章长度
	F(i,0,n) {
		cin >> x;
		if(inqueue[x] == false) {
			cnt++;
			q.push(x);
			inqueue[x] = true;
		}
		if(q.size() > m) {
			inqueue[q.front()] = false;
			q.pop();
		}
	}
	cout << cnt << endl;
	return 0;
}

5. 反倍数

题意

给定三个整数 a, bc,如果一个整数既不是 a 的整数倍也不是 b 的整数倍还不是 c 的整数倍,则这个数称为反倍数。

image.png 请问在 1 至 n 中有多少个反倍数。

image.png

image.png

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
	1到30有多少个反倍数, 2, 3, 6
	1  5  7 11 13 17 19 23 25 29
	cnt = 10
	
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dd80b53f42fb456dbbf4c47c0f39d2dc~tplv-k3u1fbpfcp-watermark.image?)
	1.定义变量cnt=0, a, b, c, n
	2. 输入n,a,b,c
	2. for i=1 to n, do:
		a. 如果i不是a、b和c的倍数,cnt加1
*/

int main() {
	ios::sync_with_stdio(false);
	int cnt = 0, a, b, c, n;
	cin >> n >> a >> b >> c;
	F(i,1,n+1) {
		if(i%a && i%b && i%c)
			cnt++;
	}
	cout << cnt;
	return 0;
}

6.凯撒密码

题目描述

image.png

输入输出

image.png

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
    单词中的所有字母都后移3位
    a变成d
    b变成e
    z变成c
    
    1. 定义字符串s
    2. 输入s
    3. 遍历字符串,重复做:
		a.如果遇到字符z, 就将字符变成c
		b.否则如果遇到字符x,就将字符变成a
		c.否则如果遇到字符y,就将字符变成b
		d.否则,每个字符都加3
*/

int main() {
	ios::sync_with_stdio(false);
	string s;
	cin >> s;
	F(i,0,s.size()) {
		if(s[i] == 'z')
			 s[i] = 'c';
		else if(s[i] == 'y')
			 s[i] = 'b';
		else if(s[i] == 'x')
			 s[i] = 'a';
		else
			s[i] += 3;
	}
	cout << s;
	return 0;
}

第二种写法

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
    单词中的所有字母都后移3位
    a变成d
    b变成e
    z变成c
    
    1. 定义字符串s
    2. 输入s
    3. 遍历字符串,重复做:
		a.如果遇到字符z, 就将字符变成c
		b.否则如果遇到字符x,就将字符变成a
		c.否则如果遇到字符y,就将字符变成b
		d.否则,每个字符都加3
*/

int main() {
	ios::sync_with_stdio(false);
	string s;
	cin >> s;
	F(i,0,s.size()) {
		if(s[i]>='x' && s[i] <= 'z')
			s[i] -= 23;
		else
			s[i] += 3;
	}
	cout << s;
	return 0;
}

7.约数个数

题目

image.png

代码

#include <iostream>
#define pragama GCC optimize(2)
#define F(i,a,b) for(int i = a; i < b; i++)
using namespace std;
const int N = 100;
int a[N] = {0};
/*
	16有多少个约数
	1*2*3*4 =>  1*2*3*2*2 => 2^3 * 3^1
	约数:先将一个数字分解成n个质因数,然后将(质数的幂+1)相乘
	约数个数 = (3+1)*(1+1) = 8
	
	120有多少个约数
	先将120分解成多个质因数: 2*2*2*3*5 => 2^3 * 3^1 * 5^1
	约数个数 = (3+1)*(1+1)*(1+1) = 16
	
	1. 定义变量num, res = 1(累乘器,用来累乘质因数的幂加1),数组a
	2. 输入num
	3. for i=2 to num, do: (分解质因数)
          只要i能被num整除,do:
			a.下标i对应的数组值加1,表示下标i有多少个数
			b. num 等于 num除以i
	4. 遍历数组a,do:
          如果下标i对应的数组元素不等于0,就将质因数幂+1累乘到res种
	5. 输出res
*/
int main()
{
  ios::sync_with_stdio(false);
  int num = 1200000;
    int res = 1;
    for(int i = 2; i <= num; i++) {
    while(num % i == 0) {
       a[i]++;
       num /= i;
    }
  }
  F(i,0, 100) {
    if(a[i])
      res *= a[i] + 1;
      // cout << a[i] << " ";
  }
  cout << res;
  return 0;
}

8.阶乘约数

其实就是约数题外边再套一层for循环,i从阶乘的最大数开始,比如求阶乘(100)的约数,i就从100开始,只要i不等于0,迭代条件n=--i

题目

定义阶乘 n! = 1 × 2 × 3 × · · · × n!=1×2×3×⋅⋅⋅×n。

请问 100! (100 的阶乘)有多少个正约数。

代码

#include <iostream>
#define F(i,a,b) for(int i = a; i < b; i++)
#define pragma GCC optimize(2)
#define LL long long
using namespace std;
int factor[100] = {0};
/*
	16有多少个约数
	1*2*3*4 =>  1*2*3*2*2 => 2^3 * 3^1
	约数:先将一个数字分解成n个质因数,然后将(质数的幂+1)相乘
	约数个数 = (3+1)*(1+1) = 8

	120有多少个约数
	先将120分解成多个质因数: 2*2*2*3*5 => 2^3 * 3^1 * 5^1
	约数个数 = (3+1)*(1+1)*(1+1) = 16

	1. 定义变量num, res = 1(累乘器,用来累乘质因数的幂加1),数组a
	2. 输入num
	3. for i=num; 只要i不等于0, n=--i, do:
		     4. for =2 to num, do: (分解质因数)
	              只要j能被num整除,do:
				a.下标j对应的数组值加1,表示下标j有多少个数
				b. num 等于 num除以i
		4. 遍历数组a,do:
	          如果下标i对应的数组元素不等于0,就将质因数幂+1累乘到res中
		5. 输出res
*/
LL findFactor(int n) {
  LL res = 1; //累乘器
  //从n开始
  for(int i = n; i; n = --i) {
	 for(int j = 2; j <= n; j++) {
	 	//只要n%k等于0
	 	while(n % j == 0) {
			factor[j]++;
			n /= j;
		 }
	 }
  }
  F(i,0,100) {
  	if(factor[i])
		res *= factor[i] + 1;
  }
  return res;
}

int main() {
	ios::sync_with_stdio(false);
	cout << findFactor(100);
	return 0;
}

9.斐波那契数列最大公约数

fib(gcd(m,n))

题目

斐波那契数列最大公约数

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <cmath>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
    求斐波那契数列的最大公约数 gcd
	1. 定义最大公约数函数gcd(int m, int n)
			a. 如果除数n等于0,就返回被除数m
			b. 否则(n不为0),返回gcd(n, m % n),
			被除数不断变成小的除数,除数变成被除数%除数
   2. 定义fib函数(int n)
			a. 定义变量p用来先记录,后返回,定义数组a, a[1]=1,a[2]=1
			b. 如果a[n]不等于0,就返回a[n] //查找到有,直接返回
			c. 将递归公式fib(n-1)+fib(n-2)赋值给p
			d. 将p的值赋值给a[n]
			e. 返回p
   3. 定义变量n,m
   4. 输出fib(gcd(n,m)) 将gcd函数套到fib函数里,这就是fib数列的最大公约数
*/
const int N = 1000000;
int a[N];
int gcd(int a, int b) {
    if(a % b)
        return gcd(b, a % b);
    else return b;
}
LL fib(int n) {
    LL p;
    a[1] = a[2] = 1;
    if(a[n] != 0)
        return a[n]; //查找到有,直接返回
    p = fib(n - 1) + fib(n - 2);
    a[n] = p; //先记录后返回
    return p;
}
int main() {
    ios::sync_with_stdio(false);
    cout << fib(gcd(2020,520));
    return 0;
}

10. 长草(多源bfs)

题目

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
// 2~1000
/*
    小数点.为空地,g表示长了草
    草会往上下左右四个方向长,原来的空地会变成草
    输出k个月后的图

    多源bfs,多个起点,把g入队
    1. 定义笛卡尔坐标dx和dy,存放地图的二维字符数组g,二维数组vis表示标记访问过的点
        n,m,k(n行m列k个月), 坐标结构体node{a,b,step}, 存放坐标的队列q
	2. 输入n,m
	3. 遍历二维地图,输入二维数组
	4. 输入k
	5. 定义bfs函数()
			a.枚举二维地图,如果是草g(有多个草的坐标要入队列,所以需要遍历整张图)
					a-1. 就加入队列
					a-2. 标记访问过了
            b. 只要队列不为空,do:
				b-1. 取队首元素赋值给结构体坐标变量tmp
				b-2. 弹出队首元素
				b-3. 如果到了k个月,就退出(根据step来判断)
				b-4. 遍历起点的上下左右四个方向,do:
					   c-1. 新坐标(xx,yy)等于各自的起点坐标加上移动的距离
					   c-2. 过滤掉坐标越界的情况
					   c-3. 如果草g的新坐标(xx,yy)是原来的空地.
							c-3-1. 就将原来的空地变成草地g
							c-3-2. 将新坐标入队,步长+1
							c-3-2. 标记访问过了
	6. 调用bfs函数
	7. 遍历二维地图,输出二维数组
*/
const int N = 1005;
//上下左右
int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
int n,m,k; //n行m列,k个月
char g[N][N];//存放地图
int vis[N][N] = {0}; //标记访问过的点
//坐标
struct node {
    int a, b, step;
};
queue<node> q;
void bfs() {
    //枚举,如果是g,就加入队列
    F(i,1,n+1) {
        F(j,1,m+1) {
            if(g[i][j] == 'g') {
                q.push({i,j,0});
                vis[i][j] = 1;
            }
        }
    }
    //只要队列不为空
    while(q.size()) {
        node tmp = q.front();
        q.pop();
        if(tmp.step == k)
            return;
        for(int i = 0; i < 4; i++) {
            int xx = dx[i] + tmp.a;
            int yy = dy[i] + tmp.b;
            //过滤掉坐标越界的情况
            if(xx<1 || xx>n || yy<1 || yy>m)
                continue;
            //将g的上下左右都变成g
            if(g[xx][yy] == '.') {
                g[xx][yy] = 'g';
                q.push({xx,yy,tmp.step+1});
                vis[xx][yy] = 1;
            }

        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    F(i,1,n+1) {
        F(j,1,m+1) {
            cin >> g[i][j];
        }
    }
    cin >> k;
    bfs();
    F(i,1,n+1) {
        F(j,1,m+1) {
            cout << g[i][j];
        }
        cout << endl;
    }
    return 0;
}

11. 数字9

题目

1到2019有多少个数位中包含9,1999虽然有3个9,但只算一个数位中包含9

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <sstream>
#include <string>
#include <string.h>
#include <cstring>
#include <vector>
#define F(i,a,b) for(int i = a; i < b; i++)
#define LL long long
#pragma GCC optimize(2)
using namespace std;
/*
    1~2019有多少个数位中包含数字9
    只要包含9,就算一个数,如1999算一个数包含9

    9 == 9
    9 == 9
    9 == 9
    1 == 9
    方法
    1. 不断拿个位数去与9比较,只要有一个等于9,计算器就+1
*/

int has9(int n) {
    //955
    while(n) {
        if(n % 10 == 9) {
            return 1;
        }
        n /= 10;
    }
    return 0;
}
LL cnt9(int x, int n) {
    LL cnt = 0;
    for(int i = x; x <= n; x++) {
        if(has9(x))
            cnt++;
    }
    return cnt;
}
int main() {
    ios::sync_with_stdio(false);
    cout << cnt9(1,2019);
    return 0;
}