模拟专题(普及- — 普及+)
模拟通常比较简单,所以经常会作为第一题进行考察
P1724 东风谷早苗
高中的时候最喜欢的角色之一就是早苗了, 我还买了个早苗的抱枕,hh。
分析
- 按照题目的意思,我们就是根据字符移动对应次数
显然我们时不需要完全的模拟,只需要计算出一次完整的运动后
x 与 y的变化量然后 x 循环的次数 再加上 剩余的移动即可
代码
#include <iostream>
#include <map>
#include <string>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
map<char, PII> p;
string s;
int sec;
void operator+=(PII& a, PII& b) {
a.x += b.x;
a.y += b.y;
}
void operator*= (PII& a, int& nums) {
a.x *= nums;
a.y *= nums;
}
int main() {
p['E'] = { 1, 0 };
p['S'] = { 0, -1 };
p['W'] = { -1, 0 };
p['N'] = { 0, 1 };
cin >> s >> sec;
int once = s.size(), nums = sec / s.size();
PII pos = { 0, 0 };
for (auto e : s)
pos += p[e];
pos *= nums;
for (int i = 0; i < sec % s.size(); ++i) {
pos += p[s[i]];
}
cout << pos.x << " " << pos.y << endl;
return 0;
}
P2615 神奇的幻方
分析
- 就是开一个足够大的数组 然后按照题目描述进行填充即可
代码
#include <iostream>
#include <map>
using namespace std;
#define x first
#define y second
const int N = 40;
typedef pair<int, int> PII;
int g[N][N];
int n;
map<int, PII> pos;
PII cal(int z) {
auto t = pos[z];
int x = t.x, y = t.y;
if (x == 0 && y != n - 1) return { n - 1, y + 1 };
else if (y == n - 1 && x != 0) return { x - 1, 0 };
else if (x == 0 && y == n - 1) return { x + 1, y };
else if (g[x - 1][y + 1] == 0) return { x - 1, y + 1 };
else return { x + 1, y };
}
int main() {
cin >> n;
g[0][n / 2] = 1;
pos[1] = { 0, n / 2 };
for (int i = 2; i <= n * n; ++i) {
auto t = cal(i - 1);
g[t.x][t.y] = i;
pos[i] = { t.x, t.y };
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j)
cout << g[i][j] << " ";
puts("");
}
return 0;
}
P8870 B-莲子的机械动力学
- 分析
这题本质就是一个高精度加法, 但是注意考虑特殊进制
代码
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int N = 200010;
vector<int> s1, s2;
int n, m;
vector<int> a, b;
vector<int> add(vector<int>& a, vector<int>& b) {
if (a.size() < b.size()) return add(b, a);
vector<int> res;
for (int i = 0, t = 0; i < a.size() || t; ++i) {
if (i < a.size()) t += a[i];
if (i < b.size()) t += b[i];
res.push_back(t % (i + 2));
t /= i + 2;
}
while (res.size() > 1 && !res.back()) res.pop_back();
return res;
}
void input(vector<int>& s, int n) {
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
s.push_back(x);
}
}
int main() {
cin >> n >> m;
int in = 0;
input(s1, n);
input(s2, m);
for (int i = s1.size() - 1; i >= 0; --i) a.push_back(s1[i]);
for (int i = s2.size() - 1; i >= 0; --i) b.push_back(s2[i]);
auto res = add(a, b);
for (int i = res.size() - 1; i >= 0; --i) cout << res[i] << " ";
return 0;
}
P1076 寻宝
分析
- 唯一值得一提的是在我们对寻找上楼房间次数优化的时候,如果恰好只需要转整数圈 (也就是%出来结果为0 )那么我们的答案其实是在该点的前一个有楼梯的房间, 所以我们可以特殊处理
f (z % nums) z %= nums;
else z = nums;
当恰好循环整数圈时 我们直接让次数等于 nums即可 (nums是该层楼有楼梯房间的个数)
代码
#include <iostream>
using namespace std;
#define x first
#define y second
const int N = 10010, M = 110;
const int MOD = 20123;
typedef pair<int, int> PII;
typedef long long LL;
PII g[N][M];
int n, m;
LL res;
void play(int q, int p) {
if (q == n) return;
res = (res + g[q][p].y) % MOD;
int nums = 0;
for (int i = 0; i < m; ++ i) {
if (g[q][i].x == 1) nums ++;
}
int z = g[q][p].y;
int i = 0;
if (g[q][p].x == 1) i ++;
//p --;
if (z % nums) z %= nums;
else z = nums;
for (; i < z;) {
p ++;
p %= m;
if (g[q][p].x == 1) i ++;
}
play(q + 1, p);
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
int x, y;
cin >> x >> y;
g[i][j] = {x, y};
}
}
int st;
cin >> st;
play(0, st);
cout << res << endl;
return 0;
}
P8676 自描述序列
分析
- 看数据个数 显然我们是没法将所有的数据存储来内存中的,但是通过观察可以发现 数据出现的个数同样满足
g(x)
函数 所有我们可以左这样的一层嵌套处理
i += g[j] * j;
这句话的意思就是(我们在加的时候直接加上重复了j次的所有数据)
j
表示当前数的长度(例如 g(2) = g(3) == 2
· g(4) == g(5) == 2
所以 j == 2 && g[j] == 2
) 也就是我们一次性跳过的是重复出现了j次的所有数
- *扩展:
由刚刚的性质可以得出, 每一层的次数其实都跟g(x)有关 所以我们完全可以继续嵌套 即让g[g[j]]
表示为 重复出现了g[g[j]]
次的 每次循环次数为g[j]
的长为j || j + 1 || j + 2 || ... ||j + g[j]
的数 对于j
怎么求不细讲(其实是可以直接求出总和的);
注:
扩展只为帮助大家理解自描述序列,理论上来说在嵌套循环足够多的情况下可以做到不开数组求出结果(嵌套越多 精度越大 2层嵌套可以精确的算出50以内的数据, 在最后一层循环不会终止的情况下 数据就是精确的!!!)
代码
#include <iostream>
using namespace std;
typedef unsigned long long ULL;
const int MOD = 1e9 + 7;
const int N = 1e7;
ULL n;
ULL res;
int g[N];
int q[N];
int main() {
cin >> n;
g[1] = 1;
g[2] = 2;
for (int i = 1, k = 1, nums = 1; i < N; ++i, nums++) {
for (int j = 0; j < g[i] && k < N; j++) {
g[k++] = nums;
}
}
for (ULL i = 1, j = 1; i <= n; j++) {
i += g[j] * j;
res += g[j];
if (i > n) {
i -= g[j] * j;
res -= g[j];
res += (n - i + 1) / j + 1;
break;
}
}
if (n < N) cout << g[n] << endl;
else cout << res << endl;
return 0;
}
P3952 时间复杂度
分析
- 为了求取时间复杂度 我们可以想到用栈去模拟循环的代码块
接下来我们分析一下实现过程中具体的细节
1 计算时间复杂度
(1) 当 x 为 n时
如果 y为n 那么时间复杂度不变
如果y为 常数 那么时间复杂度叠加
(2) 当y为n时
如果x为n 那么时间复杂度不变
如果x为常数 那么该循环不执行, 后面的循环直接跳过
(3) 当 x y 都为常数时
比较x y的大小 若x >= y 那么时间复杂度不变
否者 该循环不执行 后面的循环跳过
2 计算ERR
只有三种情况会出现ERR
(1) 当前变量前面出现过 我们可以遍历栈来排查出这种情况(注: 由于要遍历栈里的元素 所以我们需要实现自己的栈)
(2)当栈为空时要求弹出元素
(3)当函数结束时 栈不为空
代码
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int N = 1010;
char stk[N];
int top;
char T[100];
bool flag;
int isT[N];
bool check(char ch) {
for (int i = 0; i < top; ++i) {
if (stk[i] == ch) return true;
}
return false;
}
bool check(string& s) {
int i = 4;
string ch1, ch2;
bool flag1 = true;
while (i < s.size()) {
if (flag1) ch1 += s[i++];
else ch2 += s[i++];
if (s[i] == ' ') flag1 = false, i++;
}
if (ch1 == "n" && ch2 != "n") {
flag = false;
return false;
}
if (ch2 == "n" && ch1 == "n") return false;
if (ch2 == "n") return true;
if (stoi(ch1) > stoi(ch2)) flag = false;
if (ch1 == "n") return false;
return false;
}
int getNum() {
int res = 0, j = 4;
while (T[j] >= '0' && T[j] <= '9')
res = res * 10 + T[j++] - '0';
return res;
}
void clear(int& n) {
string s;
while (n--) getline(cin, s);
n = 0;
}
int main() {
int t;
cin >> t;
while (t--) {
flag = true;
top = 0;
int res = 0, temp = 0;
int n;
cin >> n;
cin >> T;
getchar();
memset(isT, 0, sizeof isT);
bool cc = false;
while (n--) {
string s;
getline(cin, s);
if (s[0] == 'F') { // 处理循环
if (check(s[2])) {
cout << "ERR" << endl;
cc = true;
clear(n);
break;
} // 变量冲突
if (check(s)) {
temp++;
res = max(res, temp);
}
else if (flag) {
isT[temp]++;
}
int F = 0, E = 0;
bool bb = false;
while (!flag) {
getline(cin, s);
n--;
if (s.size() > 1 && check(s[2])) {
cout << "ERR" << endl;
clear(n);
cc = bb = true;
break;
} // 变量冲突
if (s[0] == 'F') F++;
else if (s[0] == 'E') E++;
if (E > F) flag = true;
}
if (bb) break;
if (!E) stk[top++] = s[2];
}
else if (s[0] == 'E') {
if (top == 0) {
cout << "ERR" << endl;
cc = true;
clear(n);
break;
}
top--;
if (!isT[temp]) temp--;
else isT[temp]--;
}
}
if (cc) continue;
if (top != 0) cout << "ERR" << endl;
else if (res == 0 && T[2] == '1') cout << "Yes" << endl;
else if (T[2] == '1') cout << "No" << endl;
else {
if (res == getNum()) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
}
本次模拟专题就到此结束啦!!! 完结撒花~~~