模拟专题(普及- — 普及+)

模拟专题(普及- — 普及+)

模拟通常比较简单,所以经常会作为第一题进行考察

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;
		}
	}
}

本次模拟专题就到此结束啦!!! 完结撒花~~~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值