逐月晴月杯
A. 无限旅馆
题目描述
有一个序列 \(A=[1]\),有三种操作:
- 令 \(A\rightarrow [x,A_1,A_2,\dots,A_N]\)。
- 令 \(A\rightarrow [x,A_1,x,A_2,\dots,x,A_N]\)。
- 求 \(A_x\) 的1值或确定序列长度小于 \(x\)。
思路
由于 2 操作至多进行 \(\log\) 次,所以我们可以这样求解:
- 每次不断往前跳,如果是连续的 1 就一起跳过去。
空间复杂度 \(O(N\log N)\),时间复杂度 \(O(N\log N)\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100001;
struct Node {
int op, x;
}s[MAXN];
int q, len, f[MAXN], fa[18][MAXN], cnt[MAXN], fir[MAXN];
int Get(int i, int p) {
if(!i) {
return 1;
}else if(s[i].op == 2) {
return (p % 2 ? s[i].x : Get(f[i], p / 2));
}else if(p > cnt[i]) {
return Get(fir[i], p - cnt[i]);
}else {
for(int j = 17; j >= 0; --j) {
if(((p - 1) >> j) & 1) {
i = fa[j][i];
}
}
return s[i].x;
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> q;
len = 1;
for(int i = 1, last = 0; i <= q; ++i) {
cin >> s[i].op >> s[i].x;
f[i] = last;
if(s[i].op == 1) {
len = min(int(1e9) + 1, len + 1);
cnt[i] = 1;
fir[i] = last;
if(s[last].op == 1) {
fa[0][i] = last;
fir[i] = fir[last];
cnt[i] += cnt[last];
for(int j = 1; j <= 17; ++j) {
fa[j][i] = fa[j - 1][fa[j - 1][i]];
}
}
last = i;
}else if(s[i].op == 2) {
len = min(int(1e9) + 1, 2 * len);
last = i;
}else if(s[i].op == 3) {
cout << (s[i].x > len ? -1 : Get(last, s[i].x)) << "\n";
}
}
return 0;
}
D. 镜面迷宫
题目描述
有一个由斜着/横/竖的镜面组成的 \(N\times M\) 的迷宫,有 \(Q\) 次询问,每次询问从 \((x,y)\) 向上/下/左/右发射激光会在多少个不同的镜子上反射。
思路
可以发现,我们对迷宫建图,一定会组成一个由链/环组成的图。依次处理即可。
时空复杂度均为 \(O(NM)\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1005, dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
int n, m, q, nxt[4 * MAXN * MAXN], cnt[4 * MAXN * MAXN], in[4 * MAXN * MAXN], ans[4 * MAXN * MAXN];
bool vis[4 * MAXN * MAXN], flag[4 * MAXN * MAXN];
char c[MAXN][MAXN];
int id(int x, int y, int d) {
return d * n * m + (x - 1) * m + y;
}
bool add(int x, bool f) {
x -= (x > 3 * n * m ? 3 : (x > 2 * n * m ? 2 : (x > n * m ? 1 : 0))) * n * m;
flag[x] = flag[x + n * m] = flag[x + 2 * n * m] = flag[x + 3 * n * m] = f;
return 1;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
cin >> c[i][j];
}
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
for(int d : {0, 1, 2, 3}) {
int x = i + dx[d], y = j + dy[d], nd;
if(x >= 1 && x <= n && y >= 1 && y <= m) {
if(c[x][y] == '-') {
nd = (!d ? 1 : (d == 1 ? 0 : d));
}else if(c[x][y] == '|') {
nd = (d == 2 ? 3 : (d == 3 ? 2 : d));
}else if(c[x][y] == '/') {
nd = (!d ? 3 : (d == 1 ? 2 : (d == 2 ? 1 : 0)));
}else if(c[x][y] == '\\') {
nd = (!d ? 2 : (d == 1 ? 3 : (d == 2 ? 0 : 1)));
}
nxt[id(x, y, nd)] = id(i, j, d);
in[id(i, j, d)]++;
cnt[id(x, y, nd)] = (d != nd);
}
}
}
}
for(int i = 1; i <= 4 * n * m; ++i) {
if(!in[i]) {
int u = i, res = 0;
for(; u; ans[u] = res, vis[u] = 1, res += (cnt[u] && !flag[u]), (cnt[u] && add(u, 1)), u = nxt[u]) {
}
u = i;
for(; u; add(u, 0), u = nxt[u]) {
}
}
}
for(int i = 1; i <= 4 * n * m; ++i) {
if(!vis[i]) {
int u = i, res = 0;
for(; !vis[u]; res += (cnt[u] && !flag[u]), (cnt[u] && add(u, 1)), vis[u] = 1, u = nxt[u]) {
}
u = i;
do {
ans[u] = res;
add(u, 0);
u = nxt[u];
}while(u != i);
}
}
cin >> q;
for(int i = 1, x, y, d; i <= q; ++i) {
string s;
cin >> x >> y >> s;
d = (s == "above" ? 0 : (s == "below" ? 1 : (s == "left" ? 2 : 3)));
cout << ans[id(x, y, d)] << "\n";
}
return 0;
}