模拟,顾名思义,就是题⽬让你做什么你就做什么,考察的是将思路转化成代码的代码能⼒。 这类题⼀般较为简单,属于竞赛⾥⾯的签到题(但是,万事⽆绝对,也有可能会出现让⼈⾮常难受的 模拟题),我们在学习语法阶段接触的题,⼤多数都属于模拟题。
一、 多项式输出
题⽬来源:洛⾕
题⽬链接:P1067 [NOIP 2009 普及组] 多项式输出 - 洛谷
难度系数:★
1. 题目描述
2. 算法原理
解法:模拟+分类讨论,对于⼀元 次⽅程的的最终结果,我们仅需按照顺序,考虑每⼀项的三件事情:一项一项输出,每一项关心三个部分:符号+数+次数
处理「符号」:
- 如果系数⼩于 ,直接输出"-";
- 如果系数⼤于 ,除了⾸项不输出"+",其余全部输出"+"。
处理「系数」:
- 先取⼀个绝对值,因为正负的问题已经处理过了;
- 当系数不等于 1,直接输出这个数;
- 但是当系数为 1,且是最后⼀项的时候,这个1 也是需要输出的;其余情况下的 1不需要输 出。
处理「次数」:
- 次数⼤于 1,输出"x^"+对应的次数;
- 次数等于 1,输出"x";
- 次数⼩于 1,什么也不输出。
3. 参考代码
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n; cin >> n;
// 循环次数
for (int i = n; i >= 0; i--)
{
int a; cin >> a;
if (a == 0) continue; // 处理系数为 0 的情况
// 1. 符号
if (a < 0) cout << '-';
else
{
if (i != n) cout << '+';
}
// 2. 数字
a = abs(a);
if (a != 1 || (a == 1 && i == 0)) cout << a;
// 3. 次数
if (i == 0) continue;
else if (i == 1) cout << 'x';
else cout << "x^" << i;
}
return 0;
}
二、蛇形⽅阵
题⽬来源:洛⾕
题⽬链接:P5731 【深基5.习6】蛇形方阵 - 洛谷
难度系数:★
1. 题目描述
2. 算法原理
模拟填数的过程。
在⼀个矩阵中按照⼀定规律填数的通⽤解法:
- 定义⽅向向量,⽐如本题⼀共四个⽅向,分别是右、下、左、上,对应: (0, 1) 、 (1,0) 、 (0,−1) 、 (−1,0)
- 循环填数的规则:
- 朝⼀个⽅向⾛,⼀边⾛⼀边填数,直到越界;
a < 1 || a > n || b < 1 || b > n || arr[a][b] != 0
- 越界之后,结合定义的⽅向向量,求出下⼀轮应该⾛的⽅向以及应该到达的正确位置;
pos = (pos + 1) % 4;
a = x + dx[pos], b = y + dy[pos];
- 重复上述过程,直到把所有的数填完为⽌。
3. 参考代码
#include <iostream>
using namespace std;
const int N = 15;
// 定义 右,下,左,上 四个方向
int dx[] = { 0, 1, 0, -1 };
int dy[] = { 1, 0, -1, 0 };
int arr[N][N];
int main()
{
int n; cin >> n;
// 模拟填数过程
int x = 1, y = 1; // 初始位置
int cnt = 1; // 当前位置要填的数
int pos = 0; // 当前的方向
while (cnt <= n * n)
{
arr[x][y] = cnt;
// 计算下一个位置
int a = x + dx[pos], b = y + dy[pos];
// 判断是否越界
if (a < 1 || a > n || b < 1 || b > n || arr[a][b])
{
// 更新出正确的该走的位置
pos = (pos + 1) % 4;
a = x + dx[pos], b = y + dy[pos];
}
x = a, y = b;
cnt++;
}
// 输出
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
printf("%3d", arr[i][j]);
}
puts("");
}
return 0;
}
三、字符串的展开
题⽬来源:洛⾕
题⽬链接:P1098[NOIP2007提⾼组]字符串的展开
难度系数:★
1. 题目描述
2. 算法原理
根据规则模拟字符串展开的过程即可。
题⽬的规则较⻓,但是叙述的⾮常详细,只要把「细节」考虑到位,「分类讨论」就能搞定。
3. 参考代码
#include <iostream>
#include <algorithm>
using namespace std;
int p1, p2, p3, n;
string s;
string ret;
// 判断是否是数字字符
bool isdig(char ch)
{
return ch >= '0' && ch <= '9';
}
// 判断是否是小写字母
bool islet(char ch)
{
return ch >= 'a' && ch <= 'z';
}
// 把 [left, right] 之间的字符展开
// left, right 这两个字符是不做处理
void add(char left, char right)
{
string t;
// 遍历中间的字符
for(char ch = left + 1; ch < right; ch++)
{
char tmp = ch;
// 处理 p1
if(p1 == 2 && islet(tmp)) tmp -= 32; // 小写变大写
else if(p1 == 3) tmp = '*'; // 变成星号
// 处理 p2
for(int i = 0; i < p2; i++)
{
t += tmp;
}
}
// 处理 p3
if(p3 == 2) reverse(t.begin(), t.end());
ret += t;
}
int main()
{
cin >> p1 >> p2 >> p3 >> s;
n = s.size();
for(int i = 0; i < n; i++)
{
char ch = s[i];
if(s[i] != '-' || i == 0 || i == n - 1) ret += ch;
else
{
char left = s[i - 1], right = s[i + 1];
// 判断是否展开
if(isdig(left) && isdig(right) && right > left ||
islet(left) && islet(right) && right > left)
{
// 展开
add(left, right);
}
else
{
ret += ch;
}
}
}
cout << ret << endl;
return 0;
}