2025/7/7 cw模拟赛总结
前言
为什么没小样例(?)
。
T1 特殊字符串
为什么想不到我去了。
你发现贪心并不好记答案,考虑 dp。
记 \(f_{i}\) 表示考虑到了第 \(i\) 个字符的最大答案,记 \(v_{a,b}\) 表示字符 \(a,b\) 组成子串的总贡献。
考虑枚举与 \(s_i\) 匹配子串的字符 \(ch\),有转移 \(f_i \leftarrow \max\{pre_{ch} + v_{ch,s_i}\}\)。
其中 \(pre_{ch}\) 表示 \(ch\) 这个字符的最大贡献。
本质上是前缀最大优化了 \(O(n^2)\) 的 dp。
#include <bits/stdc++.h>
using namespace std;
#define FILEIO
#define int long long
#define IOS (ios::sync_with_stdio(0), cin.tie(0), cout.tie(0))
constexpr int N = 1e5 + 10;
char s[N], c[N][2];
int n, m, v[26][26], f[N], pre[26];
signed main() {
#ifdef FILEIO
freopen ("shiki.in", "r", stdin);
freopen ("shiki.out", "w", stdout);
#endif
IOS;
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> s[i];
}
cin >> m;
for (int i = 1, k; i <= m; i ++) {
cin >> c[i][0] >> c[i][1] >> k;
v[c[i][0] - 'a'][c[i][1] - 'a'] += k;
}
for (int i = 0; i < 26; i ++) {
pre[i] = -3e18;
}
for (int i = 1; i <= n; i ++) {
for (int ch = 0; ch < 26; ch ++) {
f[i] = max(f[i], pre[ch] + v[ch][s[i] - 'a']);
}
pre[s[i] - 'a'] = max(pre[s[i] - 'a'], f[i]);
}
int ans = -3e18;
for (int i = 1; i <= n; i ++) {
ans = max(ans, f[i]);
}
cout << ans << '\n';
return 0;
}
T2 宝可梦
大模拟。(可以这么说)
你发现由于腿残导致只能扶墙走,那么对于每个点出边的状态是固定的(指对于同一种出发方向)。
那么由此可得,既然你要对于任意不为墙的两点使得其有且仅存在一条简单路径使得两点可达,那么对于给定的出发方向整个图连出的边一定是一个大环。
那么对于每个点每个可能进来的方向建边到下一个状态,这样的边数就是 \(16nm\) 的,然后你考虑 dfs 这张图,那么算环上两点距离只需要判断 \(dfn_u,dfn_v\) 的大小作差。
#include <bits/stdc++.h>
#define int long long
#define FILEIO
#define IOS (ios::sync_with_stdio(0), cin.tie(0), cout.tie(0))
using namespace std;
// 1 : 上
// 2 : 下
// 3 : 左
// 4 : 右
constexpr int N = 2e6 + 10;
constexpr int M = 6e6 + 10;
constexpr int dx[5] = {0, -1, 1, 0, 0};
constexpr int dy[5] = {0, 0, 0, -1, 1};
int n, m, q, head[N], idx, U, dfn[N], tx, ty, tdir, tot;
char line[N];
vector<int> mp[N];
struct graph {
int to;
int nxt;
} edge[M];
void addedge(int u, int v) {
edge[idx].to = v;
edge[idx].nxt = head[u];
head[u] = idx ++;
}
int front(int dir) {
return dir;
}
int left(int dir) {
if (dir == 1) return 3;
if (dir == 2) return 4;
if (dir == 3) return 2;
if (dir == 4) return 1;
}
int right(int dir) {
if (dir == 1) return 4;
if (dir == 2) return 3;
if (dir == 3) return 1;
if (dir == 4) return 2;
}
int back(int dir) {
if (dir == 1 || dir == 2) {
return 3 - dir;
}
else {
return 7 - dir;
}
}
bool check(int x, int y) {
return x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y];
}
int ID(int x, int y, int dir) {
return (dir - 1) * n * m + (x - 1) * m + y;
}
void build() {
memset (head, -1, sizeof(head));
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
if (!check(i, j))
continue;
for (int d = 1; d <= 4; d ++) {
int st = right(d);
int x = i + dx[st], y = j + dy[st];
if (check(x, y)) {
addedge(ID(i, j, d), ID(x, y, st));
continue;
}
st = front(d);
x = i + dx[st], y = j + dy[st];
if (check(x, y)) {
addedge(ID(i, j, d), ID(x, y, st));
continue;
}
st = left(d);
x = i + dx[st], y = j + dy[st];
if (check(x, y)) {
addedge(ID(i, j, d), ID(x, y, st));
continue;
}
st = back(d);
x = i + dx[st], y = j + dy[st];
if (check(x, y)) {
addedge(ID(i, j, d), ID(x, y, st));
continue;
}
}
}
}
}
void dfs(int u) {
dfn[u] = ++tot;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int to = edge[i].to;
if (!dfn[to]) {
dfs(to);
}
}
}
int calc(int u, int v) {
int du = dfn[u], dv = dfn[v];
if (du == 0 || dv == 0) {
return 3e18;
}
if (du <= dv) {
return dv - du;
}
else {
return tot - du + dv - 1;
}
}
signed main() {
#ifdef FILEIO
freopen ("pokemon.in", "r", stdin);
freopen ("pokemon.out", "w", stdout);
#endif
IOS;
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
mp[i].push_back(0);
for (int j = 1; j <= m; j ++) {
cin >> line[j];
mp[i].push_back((line[j] == '.') ? 1 : 0);
}
}
build();
tx = -1, ty = -1;
for (int i = 1; i <= n; i ++) {
if (tx != -1 && ty != -1) {
break;
}
for (int j = 1; j <= m; j ++) {
if (tx != -1 && ty != -1) {
break;
}
if (mp[i][j]) {
for (int d = 1; d <= 4; d ++) {
int x = i + dx[d], y = j + dy[d];
if (check(x, y)) {
tx = i, ty = j, tdir = d;
break;
}
}
}
}
}
dfs(ID(tx, ty, tdir));
cin >> q;
while (q--) {
int stx, sty, edx, edy, dir;
cin >> stx >> sty >> edx >> edy >> line;
if (stx == edx && sty == edy) {
cout << "0\n";
continue;
}
if (line[0] == 'U') dir = 1;
if (line[0] == 'D') dir = 2;
if (line[0] == 'L') dir = 3;
if (line[0] == 'R') dir = 4;
int x = stx + dx[dir], y = sty + dy[dir], st = ID(x, y, dir);
int ans = 3e18;
for (int d = 1; d <= 4; d ++) {
ans = min(ans, calc(st, ID(edx, edy, d)));
}
cout << ans + 1 << '\n';
}
return 0;
}
/*
11 13
.X.....X.....
.XXX.XXX.XXX.
...X.X.X...X.
XX.X.X.XXX.XX
.........X...
.X.X.X.XXX.X.
.X.X.X.X...X.
XX.XXX.X.XXX.
...X...X...X.
.X.X.XXXXXXX.
.X.X.........
1
5 6 3 13 D
*/
T3 矩阵
首先对于点 \((i,j)\) 一定是可以处理其周围四条边权值,要求权值相等的路径最长,你发现值域只有 \(4 \times 10^4\),考虑枚举路径公比,将所有权值为所枚举公比的边加入并拓扑。
#include <bits/stdc++.h>
// #define int long long
#define pii pair<int,int>
#define mkp make_pair
#define vi vector<int>
#define vii vector<vector<int>>
#define vpii vector<pii>
#define mkp make_pair
#define FILEIO
#define fgetchar
using namespace std;
#ifdef fgetchar
char buf[1 << 23], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 23, stdin), p1 == p2) ? EOF : *p1++)
#endif
inline int read() {
int res = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) f = ch == '-' ? -1 : 1, ch = getchar();
while (isdigit(ch)) res = res * 10 + (ch ^ 48), ch = getchar();
return res * f;
}
constexpr int N = 50010;
constexpr int M = 800010;
int n, m, idx, head[N], ans[N], in[N], res;
vpii E[N];
set<int> point;
queue<int> q;
struct graph {
int to;
int nxt;
} edge[M];
void init() {
while (!q.empty()) {
q.pop();
}
point.clear(), idx = 0;
}
void addedge(int u, int v) {
edge[idx].to = v;
edge[idx].nxt = head[u];
head[u] = idx ++;
}
signed main() {
#ifdef FILEIO
freopen("matrix.in", "r", stdin);
freopen("matrix.out", "w", stdout);
#endif
n = read(), m = read();
if (n == 1 && m == 1) {
puts("1");
return 0;
}
vi num[N];
for (int i = 1; i <= n; i ++) {
num[i].push_back(0);
for (int j = 1; j <= m; j ++) {
num[i].push_back(read());
}
num[i].push_back(0);
}
bool flag = true;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
int p = (i - 1) * m + j;
if (i > 1) {
if (num[i][j] % num[i - 1][j] == 0) {
E[num[i][j] / num[i - 1][j]].push_back(mkp(p - m, p));
if (num[i][j] == num[i - 1][j]) {
flag = false;
break;
}
}
}
if (i < n) {
if (num[i][j] % num[i + 1][j] == 0) {
E[num[i][j] / num[i + 1][j]].push_back(mkp(p + m, p));
if (num[i][j] == num[i + 1][j]) {
flag = false;
break;
}
}
}
if (j > 1) {
if (num[i][j] % num[i][j - 1] == 0) {
E[num[i][j] / num[i][j - 1]].push_back(mkp(p - 1, p));
if (num[i][j] == num[i][j - 1]) {
flag = false;
break;
}
}
}
if (j < m) {
if (num[i][j] % num[i][j + 1] == 0) {
E[num[i][j] / num[i][j + 1]].push_back(mkp(p + 1, p));
if (num[i][j] == num[i][j + 1]) {
flag = false;
break;
}
}
}
}
}
if (!flag) {
puts("-1");
return 0;
}
memset (head, -1, sizeof(head));
for (int v = 2; v <= 40000; v ++) {
init();
for (auto t : E[v]) {
in[t.second] ++;
addedge(t.first, t.second);
point.insert(t.first), point.insert(t.second);
}
for (auto t : point) {
if (!in[t]) {
q.push(t);
ans[t] = 1;
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt) {
int to = edge[i].to;
ans[to] = max(ans[u] + 1, ans[to]);
in[to] --;
if (in[to] == 0) {
q.push(to);
}
}
}
for (auto t : point) {
res = max(res, ans[t]);
ans[t] = in[t] = 0;
}
for (auto t : E[v]) {
head[t.first] = head[t.second] = -1;
}
}
printf ("%d\n", res == 0 ? 1 : res);
return 0;
}

浙公网安备 33010602011771号