NOIP2023 双序列拓展
首先 显然不合法。若 就把 全部取相反数,这样就只用考虑 的情况了。
然后考虑一个 的 dp,设 为拓展 的前 个元素和 的前 个元素是否可行。那么若 则 取 的或,否则 。
发现这个 dp 的转移形式很像网格上行走,于是考虑转成网格上的问题。考虑令 ,那么可行当且仅当能找到一条从 到 的全为 的八连通的路径。
注意到任意两行之间 的位置总是包含关系,这意味着不用考虑斜着走,即 走到 ,因为可以被 或 的其中一个代替。于是只用考虑四连通的路径。
考虑从特殊性质入手,即网格第 行和第 列全为 (如果不全为 一定不可行),这样只要到达第 行或第 列就赢了。考虑递归求解,设 为当前在 ,是否能到达第 行或第 列。设 。若第 列全为 则可以直接递归至 ,若第 列全为 则可以直接递归至 ;若都不满足,则网格一定存在一个以 组成的十字架,把起点和终点隔开,于是这种情况直接返回不可行。所有要用到的信息都能预处理 的前缀 数组然后 求出,所以复杂度为 。
对于一般的情况,考虑设 ,那么第 行和第 列一定要全为 。容易发现网格被第 行和第 列分成了左上角和右下角两个互相独立的部分,于是把右下角的部分翻转过来,做一遍同样的问题即可。
总时间复杂度就是 。
code
#include <bits/stdc++.h> #define fst first #define scd second #define pb emplace_back #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef double db; typedef long double ldb; inline int read() { int x = 0; bool f = 0; char c = getchar(); while (c < '0' || c > '9') { f |= (c == '-'); c = getchar(); } while ('0' <= c && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return f ? -x : x; } const int maxn = 500100; const int inf = 0x3f3f3f3f; int n, m, q, test, a[maxn], b[maxn]; int c[maxn], d[maxn]; pii pcmn[maxn], pcmx[maxn], pdmn[maxn], pdmx[maxn]; pii scmn[maxn], scmx[maxn], sdmn[maxn], sdmx[maxn]; int dfs1(int x, int y) { if (x == 1 || y == 1) { return 1; } int p1 = pcmn[x - 1].scd, p2 = pdmx[y - 1].scd; if (c[p1] < pdmn[y - 1].fst) { return dfs1(p1, y); } else if (pcmx[x - 1].fst < d[p2]) { return dfs1(x, p2); } else { return 0; } } int dfs2(int x, int y) { if (x == n || y == m) { return 1; } int p1 = scmn[x + 1].scd, p2 = sdmx[y + 1].scd; if (c[p1] < sdmn[y + 1].fst) { return dfs2(p1, y); } else if (scmx[x + 1].fst < d[p2]) { return dfs2(x, p2); } else { return 0; } } inline int calc() { if (c[1] == d[1]) { return 0; } if (c[1] > d[1]) { for (int i = 1; i <= n; ++i) { c[i] = -c[i]; } for (int i = 1; i <= m; ++i) { d[i] = -d[i]; } } pcmn[0].fst = pdmn[0].fst = inf; pcmx[0].fst = pdmx[0].fst = -inf; for (int i = 1; i <= n; ++i) { pcmn[i] = min(pcmn[i - 1], mkp(c[i], i)); pcmx[i] = max(pcmx[i - 1], mkp(c[i], i)); } for (int i = 1; i <= m; ++i) { pdmn[i] = min(pdmn[i - 1], mkp(d[i], i)); pdmx[i] = max(pdmx[i - 1], mkp(d[i], i)); } scmn[n + 1].fst = inf; sdmn[m + 1].fst = inf; scmx[n + 1].fst = -inf; sdmx[m + 1].fst = -inf; for (int i = n; i; --i) { scmn[i] = min(scmn[i + 1], mkp(c[i], i)); scmx[i] = max(scmx[i + 1], mkp(c[i], i)); } for (int i = m; i; --i) { sdmn[i] = min(sdmn[i + 1], mkp(d[i], i)); sdmx[i] = max(sdmx[i + 1], mkp(d[i], i)); } int p1 = pcmn[n].scd, p2 = pdmx[m].scd; for (int i = 1; i <= m; ++i) { if (c[p1] >= d[i]) { return 0; } } for (int i = 1; i <= n; ++i) { if (c[i] >= d[p2]) { return 0; } } return dfs1(p1, p2) && dfs2(p1, p2); } void solve() { test = read(); n = read(); m = read(); q = read(); for (int i = 1; i <= n; ++i) { a[i] = read(); } for (int i = 1; i <= m; ++i) { b[i] = read(); } for (int i = 1; i <= n; ++i) { c[i] = a[i]; } for (int i = 1; i <= m; ++i) { d[i] = b[i]; } putchar('0' + calc()); while (q--) { for (int i = 1; i <= n; ++i) { c[i] = a[i]; } for (int i = 1; i <= m; ++i) { d[i] = b[i]; } int kx, ky; kx = read(); ky = read(); while (kx--) { int x, y; x = read(); y = read(); c[x] = y; } while (ky--) { int x, y; x = read(); y = read(); d[x] = y; } putchar('0' + calc()); } putchar('\n'); } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
有小丑场上把
for (int i = 1; i <= n; ++i) { c[i] = a[i]; } for (int i = 1; i <= m; ++i) { d[i] = b[i]; }
写成了
for (int i = 1; i <= n; ++i) { c[i] = a[i]; d[i] = b[i]; }
暴挂 分,怎么会是呢。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App