EC-Final-2021
A. DFS Order
签到题,最小值是深度,最大值是总点数减去子树大小,跑一个dfs就行。
code for A
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, dep[N], siz[N], ans[N][2];
vector<int> G[N];
void dfs(int u, int f) {
dep[u] = dep[f] + 1, siz[u] = 1;
for(auto v : G[u]) if(v != f) {
dfs(v, u), siz[u] += siz[v];
}
ans[u][0] = dep[u], ans[u][1] = n - siz[u] + 1;
}
inline void solve() {
cin >> n;
for(int i = 1; i < n; i ++) {
int a, b; cin >> a >> b;
G[a].emplace_back(b), G[b].emplace_back(a);
}
dfs(1, 0);
for(int i = 1; i <= n; i ++)
cout << ans[i][0] << ' ' << ans[i][1] << '\n';
for(int i = 1; i <= n; i ++) G[i].clear();
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) solve();
return 0;
}
B. Beautiful String
套路串串,
具体的,设串长
即可做到
然后枚举
code for B
#include <bits/stdc++.h>
using namespace std;
const int N = 5010;
int n, lcp[N][N], siz[N]; string S;
inline void solve() {
cin >> S; n = S.size(), S = "$" + S;
for(int i = 0; i <= n + 1; i ++) lcp[n + 1][i] = lcp[i][n + 1] = 0;
for(int i = n; i >= 1; i --) for(int j = n; j >= 1; j --)
lcp[i][j] = (S[i] == S[j] ? lcp[i + 1][j + 1] + 1 : 0);
long long ans = 0;
for(int i = 2; i <= n; i ++) {
for(int j = 0; j <= n - i + 2; j ++) siz[j] = 0;
for(int j = i + 3; j <= n; j ++)
if(lcp[i][j] >= 2) siz[min(lcp[i][j] - 1, j - i - 2)] ++;
long long sum = 0, cnt = 0;
for(int j = n - i + 1; j >= 1; j --) {
cnt += siz[j], sum += cnt;
if(j < i && lcp[i - j][i] >= j) ans += sum;
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) solve();
return 0;
}
C. String-dle Count
根据给出来的东西,可以得知每个位置被禁止填哪些字母、每个字母至多被填多少个(存在该字母的-
且不存在该字母的x
的时候)或者应该恰好被填多少个(存在该字母的x
时),顺便判一下矛盾。
设字母
现在
对于后者的转移,我们可以预处理一下做到
代码如下,solve
函数中的
code for C
#include <bits/stdc++.h>
using namespace std;
const int N = 20, MOD = 1e9 + 7;
inline int Plus(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b; }
inline int Minus(int a, int b) {return a - b < 0 ? a - b + MOD : a - b; }
inline int ksm(long long a, int b) {
long long r = 1;
for(; b; b >>= 1, a = a * a % MOD)
if(b & 1) r = r * a % MOD;
return r;
}
int n, ban[N], L[26], R[26];
int f[N][1 << N];
inline int solve() {
int T; cin >> T >> n;
for(int i = 0; i < 26; i ++) L[i] = 0, R[i] = n;
while(T --) {
string A, B; cin >> A >> B;
vector<int> siz(26, 0);
for(int i = 0; i < n; i ++) if(B[i] == 'O') {
siz[A[i] - 'A'] ++;
ban[i] |= ((1 << 26) - 1) ^ (1 << A[i] - 'A');
}
for(int i = 0; i < n; i ++) if(B[i] != 'O') {
if(B[i] == '-') L[A[i] - 'A'] = max(L[A[i] - 'A'], ++siz[A[i] - 'A']);
else R[A[i] - 'A'] = min(R[A[i] - 'A'], siz[A[i] - 'A']);
ban[i] |= 1 << (A[i] - 'A');
}
for(int i = 0; i < 26; i ++) L[i] = max(L[i], siz[i]);
}
for(int i = 0; i < 26; i ++)
if(L[i] > R[i]) return 0;
int least = 0;
for(int i = 0; i < 26; i ++)
least += L[i];
if(least > n) return 0;
static int in[N], trans[1 << N];
for(int i = 0, tot = 0; i < 26; i ++) {
for(int j = 0; j < L[i]; j ++)
in[tot ++] = i;
}
memset(trans, 0, sizeof trans);
for(int mask = 0; mask < (1 << least); mask ++) {
for(int i = 0, tot = 0; i < 26; i ++) {
int siz = 0;
for(int j = 0; j < L[i]; j ++)
siz += (mask >> tot & 1), tot ++;
if(siz == L[i] && L[i] < R[i]) trans[mask] |= 1 << i;
}
}
f[0][0] = 1;
for(int i = 1; i <= n; i ++) {
for(int mask = 0; mask < (1 << least); mask ++) if(f[i - 1][mask]) {
for(int j = 0; j < least; j ++) if(!(mask >> j & 1) && (j == 0 || in[j] != in[j - 1] || (mask >> j - 1 & 1))) {
int ch = in[j]; if(ban[i - 1] >> ch & 1) continue;
f[i][mask | (1 << j)] = Plus(f[i][mask | (1 << j)], f[i - 1][mask]);
}
int T = trans[mask]; T = T ^ (T & ban[i - 1]);
f[i][mask] = Plus(f[i][mask], 1ll * f[i - 1][mask] * __builtin_popcount(T) % MOD);
}
}
return f[n][(1 << least) - 1];
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T = 1;// cin >> T;
while(T --)
cout << solve() << '\n';
return 0;
}
D. Two Walls
首先,假如
当没有线段
加上线段
否则,两条线段均与
code for D
#include <bits/stdc++.h>
using namespace std;
struct Point {
long long x, y;
Point(long long _x = 0, long long _y = 0): x(_x), y(_y) {}
};
istream& operator >> (istream &in, Point &p) {in >> p.x >> p.y; return in; }
ostream& operator << (ostream& out, Point &p) {cout << p.x << ' ' << p.y; return out; }
typedef Point Vector;
Vector operator + (const Point lhs, const Vector rhs) {return Point(lhs.x + rhs.x, lhs.y + rhs.y); }
Vector operator - (const Point lhs, const Vector rhs) {return Point(lhs.x - rhs.x, lhs.y - rhs.y); }
inline long long Cross(const Vector lhs, const Vector rhs) {return lhs.x * rhs.y - lhs.y * rhs.x; }
inline bool direction(const Vector u, const Vector v) {return Cross(u, v) > 0; }
inline bool direction(const pair<Point, Point> L, const Point p) {return direction(L.second - L.first, p - L.first); }
inline int intersect(const pair<Point, Point> A, const pair<Point, Point> B) {
if(max(A.first.x, A.second.x) < min(B.first.x, B.second.x)) return 0;
if(max(A.first.y, A.second.y) < min(B.first.y, B.second.y)) return 0;
if(max(B.first.x, B.second.x) < min(A.first.x, A.second.x)) return 0;
if(max(B.first.y, B.second.y) < min(A.first.y, A.second.y)) return 0;
if((__int128)Cross(B.second - B.first, A.first - B.first) * Cross(B.second - B.first, A.second - B.first) > 0)
return 0;
if((__int128)Cross(A.second - A.first, B.first - A.first) * Cross(A.second - A.first, B.second - A.first) > 0)
return 0;
if(Cross(A.second - A.first, B.first - A.first) == 0 || Cross(A.second - A.first, B.second - A.first) == 0)
return 1;
else return 2;
}
inline bool check(const pair<Point, Point> L, const pair<Point, Point> T) {
return direction(T.first - L.first, T.second - L.second) && direction(T.second - L.first, T.first - L.second);
}
inline int solve() {
Point A, B, C, D, E, F;
cin >> A >> B >> C >> D >> E >> F;
int tot = intersect({A, B}, {C, D}) + intersect({A, B}, {E, F});
if(tot == 0) return 0;
else if(tot != 4) return 1;
if(direction({A, B}, D)) swap(C, D);
if(direction({A, B}, F)) swap(E, F);
return (check({A, B}, {C, E}) || check({B, A}, {D, F})) ? 1 : 2;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --)
cout << solve() << '\n';
return 0;
}
E. Prof. Pang and Poker
假如Alice只有一张牌或者Alice的牌全部不小于Pang,那么Bob获胜,因为Bob可以一直不出牌让Alice出完。
否则假如Bob手里有至少两个小于Pang的牌,那么Pang获胜,因为Bob手中小于Pang的牌必须最后一个出,使得Bob出完牌获胜,但此时两张牌是做不到同时出去的,Alice也可以一直跳过来让Bob手中只有小于Pang的牌(注意此时已经判掉Alice的牌全部不小于Pang的情况了,也就是这时候Alice一定可以出一张牌使得Bob必须出牌,然后Pang和Alice跳过,让Bob一直出)。
否则假如Bob手里没有小于Pang的牌,显然Bob获胜。
此时Bob手中恰有一张牌是小于Pang的,Bob的目标是让它最后一个被打出。
先判掉
否则Bob一定能赢吗?不是这样的。Alice手中假如有多于
否则Bob获胜。
下面给出了单次询问
code for E
#include <bits/stdc++.h>
using namespace std;
inline int get(char c) {
if(c >= '2' && c <= '9')
return c - '2';
if(c == 'T') return 8;
if(c == 'J') return 9;
if(c == 'Q') return 10;
if(c == 'K') return 11;
if(c == 'A') return 12;
assert(false); return -1;
}
inline string solve() {
int n, m;
cin >> n >> m;
vector<int> A(n), B(m); int C;
for(int i = 0; i < n; i ++) {
string str; cin >> str;
A[i] = get(str[0]);
}
for(int i = 0; i < m; i ++) {
string str; cin >> str;
B[i] = get(str[0]);
}
{
string str; cin >> str;
C = get(str[0]);
}
int minA = A[0], maxB = B[0];
for(int i = 0; i < n; i ++) minA = min(minA, A[i]);
for(int i = 0; i < m; i ++) maxB = max(maxB, B[i]);
int cnt = 0;
for(int i = 0; i < m; i ++)
cnt += B[i] < C;
if(minA >= C || n == 1) return "Shou";
if(cnt >= 2) return "Pang";
if(cnt == 0) return "Shou";
int passA = minA;
for(int i = 0; i < n; i ++)
if(A[i] < C) passA = max(passA, A[i]);
if(m == 1) return passA >= B[0] ? "Pang" : "Shou";
sort(A.begin(), A.end()), sort(B.begin(), B.end());
if(A.back() > B.back() && n > 3 && A[1] < C && passA >= B[0]) return "Pang";
return "Shou";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) cout << solve() << '\n';
return 0;
}
F. Vacation
这种东西没有思路就先分个块就做完了。先把
先在整个序列上建一个没有长度限制的,可以单点修改+区间查询最大子段和的线段树,然后再建一个序列长
但是我们还忽略了跨越两个块的子段和,考虑往之前的做法里打补丁。对每个块边界,维护以它为左端点的,长度
形式化地,对于分割点
这个关于区间的式子是可以用线段树维护的,代表区间
注意单点修改对
最后的收尾工作就是再维护一个单点修改、查询区间
修改操作对四类线段树分别维护,查询操作多分类讨论一下即可,详细实现可以看代码。总时间复杂度
code for F
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 10;
const long long INF = 0x3f3f3f3f3f3f3f3fLL;
int n, m, c, A[N], B;
#define lc (u << 1)
#define rc (u << 1 | 1)
#define mid ((l + r) >> 1)
struct Max_Seg {
ll C[N << 2];
void Modify(int u, int l, int r, int p, ll x) {
if(l == r) return C[u] = x, void();
if(p <= mid) Modify(lc, l, mid, p, x);
else Modify(rc, mid + 1, r, p, x);
C[u] = max(C[lc], C[rc]);
}
ll Ask(int u, int l, int r, int L, int R) {
if(l >= L && r <= R) return C[u];
if(mid >= R) return Ask(lc, l, mid, L, R);
if(mid < L) return Ask(rc, mid + 1, r, L, R);
return max(Ask(lc, l, mid, L, R), Ask(rc, mid + 1, r, L, R));
}
} Block, Other;
namespace SegmentTree {
struct node {
ll l, r, s, v;
node(ll _v = 0) {l = r = v = max(_v, 0ll), s = _v; }
node(ll _l, ll _r, ll _s, ll _v): l(_l), r(_r), s(_s), v(_v) {}
};
node operator + (const node &lhs, const node &rhs) {
return node(max(lhs.l, lhs.s + rhs.l), max(rhs.r, rhs.s + lhs.r), lhs.s + rhs.s,
max(lhs.r + rhs.l, max(lhs.v, rhs.v)));
}
node T[N << 2];
void Build(int u, int l, int r) {
if(l != r)
Build(lc, l, mid), Build(rc, mid + 1, r), T[u] = T[lc] + T[rc];
else T[u] = node(A[l]);
}
void Modify(int u, int l, int r, int p, ll x) {
if(l == r) return T[u] = node(x), void();
if(p <= mid) Modify(lc, l, mid, p, x);
else Modify(rc, mid + 1, r, p, x);
T[u] = T[lc] + T[rc];
}
node Ask(int u, int l, int r, int L, int R) {
if(l >= L && r <= R) return T[u];
if(mid >= R) return Ask(lc, l, mid, L, R);
if(mid < L) return Ask(rc, mid + 1, r, L, R);
return Ask(lc, l, mid, L, R) + Ask(rc, mid + 1, r, L, R);
}
}
struct Little_SegTree {
struct node {
ll ans, pre, suf;
node(ll _ans = -INF, ll _pre = 0, ll _suf = 0): ans(_ans), pre(_pre), suf(_suf) {}
node operator + (const node &rhs) {
return node(max(this->pre + rhs.suf, max(this->ans, rhs.ans)), max(this->pre, rhs.pre), max(this->suf, rhs.suf));
}
};
node *T; ll *tag_pre, *tag_suf;
inline void init(int n) {
T = (node*)calloc(n << 2, sizeof(node));
tag_pre = (ll*)calloc(n << 2, sizeof(ll));
tag_suf = (ll*)calloc(n << 2, sizeof(ll));
}
void Build(int u, int l, int r, ll pre[], ll suf[]) {
tag_pre[u] = tag_suf[u] = 0;
if(l != r) {
Build(lc, l, mid, pre, suf), Build(rc, mid + 1, r, pre, suf);
T[u] = T[lc] + T[rc];
} else T[u] = node(pre[l] + suf[l], pre[l], suf[l]);
}
inline void Tag(int u, ll a, ll b) {
tag_pre[u] += a, tag_suf[u] += b;
T[u].pre += a, T[u].suf += b, T[u].ans += a + b;
}
inline void pushdown(int u) {
if(!tag_pre[u] && !tag_suf[u]) return;
Tag(lc, tag_pre[u], tag_suf[u]), Tag(rc, tag_pre[u], tag_suf[u]);
tag_pre[u] = tag_suf[u] = 0;
}
void Add(int u, int l, int r, int L, int R, ll a, ll b) {
if(l >= L && r <= R) return Tag(u, a, b);
pushdown(u);
if(mid >= L) Add(lc, l, mid, L, R, a, b);
if(mid < R) Add(rc, mid + 1, r, L, R, a, b);
T[u] = T[lc] + T[rc];
}
node Ask(int u, int l, int r, int L, int R) {
if(l >= L && r <= R) return T[u];
pushdown(u);
if(mid >= R) return Ask(lc, l, mid, L, R);
if(mid < L) return Ask(rc, mid + 1, r, L, R);
return Ask(lc, l, mid, L, R) + Ask(rc, mid + 1, r, L, R);
}
} Tree[N];
#undef lc
#undef rc
#undef mid
int L[N], R[N], ID[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m >> c;
for(int i = 1; i <= n; i ++) cin >> A[i];
n = (n + c - 1) / c * c, B = n / c;
SegmentTree::Build(1, 1, n);
for(int i = 1; i <= B; i ++) {
static long long pre[N], suf[N];
L[i] = (i - 1) * c + 1, R[i] = i * c;
for(int j = L[i]; j <= R[i]; j ++) ID[j] = i;
Block.Modify(1, 1, B, i, SegmentTree::Ask(1, 1, n, L[i], R[i]).v);
if(i > 1) {
pre[0] = suf[c] = 0;
for(int j = 1; j <= c; j ++) pre[j] = pre[j - 1] + A[L[i] - j];
for(int j = c - 1; j >= 0; j --) suf[j] = suf[j + 1] + A[L[i] + c - j - 1];
Tree[i].init(c + 1); Tree[i].Build(1, 0, c, pre, suf);
Other.Modify(1, 1, B, i, Tree[i].T[1].ans);
}
}
while(m --) {
int op, x, y; cin >> op >> x >> y;
if(op == 1) {
SegmentTree::Modify(1, 1, n, x, y);
Block.Modify(1, 1, B, ID[x], SegmentTree::Ask(1, 1, n, L[ID[x]], R[ID[x]]).v);
if(ID[x] > 1) {
Tree[ID[x]].Add(1, 0, c, 0, R[ID[x]] - x, 0, y - A[x]);
Other.Modify(1, 1, B, ID[x], Tree[ID[x]].T[1].ans);
}
if(ID[x] < B) {
Tree[ID[x] + 1].Add(1, 0, c, R[ID[x]] - x + 1, c, y - A[x], 0);
Other.Modify(1, 1, B, ID[x] + 1, Tree[ID[x] + 1].T[1].ans);
}
A[x] = y;
} else {
if(y - x + 1 > c) {
ll ans = max(SegmentTree::Ask(1, 1, n, x, x + c - 1).v, SegmentTree::Ask(1, 1, n, y - c + 1, y).v);
if(ID[x] + 1 < ID[y]) {
ans = max(ans, Block.Ask(1, 1, B, ID[x] + 1, ID[y] - 1));
if(ID[x] + 1 < ID[y] - 1) ans = max(ans, Other.Ask(1, 1, B, ID[x] + 2, ID[y] - 1));
ans = max(ans, Tree[ID[x] + 1].Ask(1, 0, c, 0, R[ID[x]] - x + 1).ans);
ans = max(ans, Tree[ID[y]].Ask(1, 0, c, R[ID[y]] - y, c).ans);
} else
ans = max(ans, Tree[ID[y]].Ask(1, 0, c, R[ID[y]] - y + 1, R[ID[x]] - x + 1).ans);
cout << ans << '\n';
} else cout << SegmentTree::Ask(1, 1, n, x, y).v << '\n';
}
}
return 0;
}
G. Check Pattern is Bad
把所有偶数列的颜色取反,那么就是要求不能有形如
WW BB
BB WW
这两种情况。
再把偶数行去反,形式就更简单了:不能形如
WW BB
WW BB
这两种情况。
显然,若某个
用一个bfs维护上面的过程,直到不能再填。如果发现了矛盾就直接结束。
接下来我们证明,此时不断重复以下操作,一定可以得到一个合法解:
- 随便找一个不知道颜色的位置
- 随便填上一个颜色
- 接着用 bfs 扩展
证明: 只需要证每次扩展bfs的时候不会出现矛盾即可。设钦定的随便填的格子为
发现
证毕!
单组数据的时间复杂度是
code for G
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m; char S[N][N];
int A[N][N];
queue<pair<int, int>> Q;
inline void check(int x, int y) {
if(x <= 0 || y <= 0 || x >= n || y >= m) return;
int siz = A[x][y] + A[x + 1][y + 1] + A[x + 1][y] + A[x][y + 1];
if(abs(siz) == 3) {
if(A[x][y] == 0) A[x][y] = -A[x + 1][y + 1], check(x - 1, y - 1);
else if(A[x + 1][y] == 0) A[x + 1][y] = -A[x][y], check(x + 1, y - 1);
else if(A[x][y + 1] == 0) A[x][y + 1] = -A[x][y], check(x - 1, y + 1);
else A[x + 1][y + 1] = -A[x][y], check(x + 1, y + 1);
}
}
inline void solve() {
cin >> n >> m;
for(int i = 1; i <= n; i ++)
cin >> (S[i] + 1);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
A[i][j] = (S[i][j] == '?' ? 0 : (S[i][j] == 'W') ? 1 : -1);
for(int i = 1; i <= n; i ++)
for(int j = 2; j <= m; j += 2) A[i][j] = -A[i][j];
for(int i = 2; i <= n; i += 2)
for(int j = 1; j <= m; j ++) A[i][j] = -A[i][j];
for(int i = 1; i < n; i ++)
for(int j = 1; j < m; j ++)
check(i, j);
for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++)
if(!A[i][j]) A[i][j] = 1, check(i, j), check(i - 1, j - 1), check(i - 1, j), check(i, j - 1);
bool flag = true;
for(int i = 1; i < n && flag; i ++)
for(int j = 1; j < m && flag; j ++) {
if(abs(A[i][j] + A[i + 1][j + 1] + A[i][j + 1] + A[i + 1][j]) == 4) flag = false;
}
if(flag) {
cout << "YES" << '\n';
for(int i = 1; i <= n; i ++)
for(int j = 2; j <= m; j += 2) A[i][j] = -A[i][j];
for(int i = 2; i <= n; i += 2)
for(int j = 1; j <= m; j ++) A[i][j] = -A[i][j];
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++)
cout << (A[i][j] == 1 ? 'W' : 'B');
cout << '\n';
}
} else cout << "NO" << '\n';
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) solve();
return 0;
}
H. Check Pattern is Good
还是像上一题一样,先把偶数行、列颜色取反,然后跑网络流。
具体的,把每个 W
,另一个表示全填B
。如果一个 W
,那么就从源点连向该 W
点,容量为 B
,就从B
点连向汇点,容量为 W
点向B
点连边,容量为
答案就是网络中容量为
code for H
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Dinic {
static const int N = 2e4 + 10;
struct edge {
int from, to, cap, flow;
edge(int u, int v, int c, int f): from(u), to(v), cap(c), flow(f) {}
};
vector<edge> edges; vector<int> G[N];
inline void AddEdge(int u, int v, int c) {
static int M;
edges.emplace_back(edge(u, v, c, 0)), edges.emplace_back(edge(v, u, 0, 0));
M = edges.size(); G[u].emplace_back(M - 2), G[v].emplace_back(M - 1);
}
inline void clear() {
edges.clear();
for(int i = 0; i < N; i ++) G[i].clear();
}
int s, t, cur[N], dist[N];
inline bool BFS() {
memset(dist, 0, sizeof dist);
dist[s] = 1; queue<int> Q; Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
for(auto i : G[u]) {
edge &e = edges[i];
if(!dist[e.to] && e.flow < e.cap)
dist[e.to] = dist[e.from] + 1, Q.push(e.to);
}
}
return dist[t];
}
int dfs(int u, int F) {
if(u == t || F <= 0) return F;
int flow = 0;
for(int &i = cur[u]; i < G[u].size(); i ++) {
edge &e = edges[G[u][i]];
if(e.cap == e.flow || dist[e.to] != dist[e.from] + 1) continue;
int f = dfs(e.to, min(F, e.cap - e.flow));
flow += f, F -= f, e.flow += f, edges[G[u][i] ^ 1].flow -= f;
if(!F) break;
}
return flow;
}
int MaxFlow(int s, int t) {
this->s = s, this->t = t;
int ans = 0;
while(BFS()) {
memset(cur, 0, sizeof cur);
ans += dfs(s, INF);
}
return ans;
}
inline void make_array(int n, int m, int A[105][105]) {
static bool vis[N];
memset(vis, false, sizeof vis);
queue<int> Q; Q.push(s), vis[s] = true;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
for(auto i : G[u]) {
edge &e = edges[i];
if(e.cap == e.flow || vis[e.to]) continue;
if(!(e.to & 1)) {
int x = e.to / 2 / m, y = e.to / 2 % m;
A[x][y] = A[x + 1][y] = A[x][y + 1] = A[x + 1][y + 1] = 1;
}
vis[e.to] = true, Q.push(e.to);
}
}
for(int i = 0; i < n; i ++)
for(int j = 0; j < m; j ++)
if(A[i][j] == 0) A[i][j] = -1;
}
} solver;
const int N = 105;
int n, m, A[N][N];
char S[N][N];
inline int get(int x, int y) {return x * m + y; }
inline void Add(int a, int b) {
solver.AddEdge(a * 2, b * 2 + 1, INF);
solver.AddEdge(b * 2, a * 2 + 1, INF);
}
inline void solve() {
cin >> n >> m;
for(int i = 0; i < n; i ++) {
cin >> S[i];
for(int j = 0; j < m; j ++)
A[i][j] = (S[i][j] == '?' ? 0 : (S[i][j] == 'W' ? 1 : -1));
}
for(int i = 0; i < n; i += 2)
for(int j = 0; j < m; j ++)
A[i][j] = -A[i][j];
for(int i = 0; i < n; i ++)
for(int j = 0; j < m; j += 2)
A[i][j] = -A[i][j];
int S = get(n - 1, m - 1) * 2 + 2, T = S + 1, ans = 0;
for(int i = 0; i < n - 1; i ++) for(int j = 0; j < m - 1; j ++) {
bool P = true, Q = true;
P = (A[i][j] != -1 && A[i + 1][j] != -1 && A[i][j + 1] != -1 && A[i + 1][j + 1] != -1);
Q = (A[i][j] != 1 && A[i + 1][j] != 1 && A[i][j + 1] != 1 && A[i + 1][j + 1] != 1);
if(P) solver.AddEdge(S, get(i, j) * 2, 1), ans ++;
if(Q) solver.AddEdge(get(i, j) * 2 + 1, T, 1), ans ++;
solver.AddEdge(get(i, j) * 2, get(i, j) * 2 + 1, INF);
if(j < m - 2) Add(get(i, j), get(i, j + 1));
if(j > 0 && i < n - 2) Add(get(i, j), get(i + 1, j - 1));
if(i < n - 2) Add(get(i, j), get(i + 1, j));
if(j < m - 2 && i < n - 2) Add(get(i, j), get(i + 1, j + 1));
}
ans -= solver.MaxFlow(S, T);
cout << ans << '\n';
solver.make_array(n, m, A), solver.clear();
for(int i = 0; i < n; i += 2)
for(int j = 0; j < m; j ++)
A[i][j] = -A[i][j];
for(int i = 0; i < n; i ++)
for(int j = 0; j < m; j += 2)
A[i][j] = -A[i][j];
for(int i = 0; i < n; i ++) {
for(int j = 0; j < m; j ++)
cout << (A[i][j] == 1 ? 'W' : 'B');
cout << '\n';
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) solve();
return 0;
}
I. Future Coder
将
code for I
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, A[N];
inline void solve() {
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> A[i], A[i] --;
int neg = 0, pos = 0, zero = 0;
for(int i = 1; i <= n; i ++) {
if(A[i] < 0) neg ++;
else if(A[i] == 0) zero ++;
else pos ++;
}
cout << 1ll * neg * pos + 1ll * zero * (neg + pos) + 1ll * zero * (zero - 1) / 2 << '\n';
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) solve();
return 0;
}
J. Elden Ring
根据
-
当
,保留点 和 的那些点 ,跑 到 的最短路。 -
当
,同样是最短路,区别在于Dijkstra扩展的时候,若到达点 时已经打不动该boss则不扩展。 -
当
,先用一个堆找出来所有可以打的点,扩展时若点 无论如何也打不了就不扩展,否则用当前距离与至少需要在第几天的时候才可以打点 上的boss的较大值更新点 的最短路。
所以只需要跑一次最短路即可,单组数据的时间复杂度为
code for J
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 2e5 + 10, M = 4e5 + 10, INF = 0x3f3f3f3f;
int n, m, A, B, l[N], h[N], e[M], ne[M], idx;
inline void add(int a, int b) {e[idx] = b, ne[idx] = h[a], h[a] = idx ++; }
namespace solver {
int dist[N]; bool st[N];
int C[N], Min[N];
inline void Dijkstra() {
memset(dist + 1, 0x3f, sizeof(int) * n);
memset(st + 1, false, sizeof(bool) * n);
dist[1] = 0;
priority_queue<pii, vector<pii>, greater<pii>> Q;
Q.push({dist[1], 1});
while(!Q.empty()) {
int u = Q.top().second; Q.pop();
if(st[u]) continue; st[u] = true;
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i]; if(st[v] || dist[u] + 1 > C[v]) continue;
if(dist[v] > max(dist[u] + 1, Min[v])) {
dist[v] = max(dist[u] + 1, Min[v]);
Q.push({dist[v], v});
}
}
}
if(dist[n] == INF) cout << "-1" << '\n';
else cout << dist[n] << '\n';
}
}
namespace solver1 {
inline void main() {
for(int i = 2; i <= n; i ++)
solver::C[i] = (l[i] < l[1] ? n + 1 : -1);
for(int i = 2; i <= n; i ++)
solver::Min[i] = -1;
solver::Dijkstra();
}
}
namespace solver2 {
inline void main() {
for(int i = 2; i <= n; i ++)
solver::C[i] = (l[i] < l[1] ? (l[1] - l[i] + B - A - 1) / (B - A) : -1);
for(int i = 2; i <= n; i ++)
solver::Min[i] = -1;
solver::Dijkstra();
}
}
namespace solver3 {
bool vis[N], ok[N];
inline int get(int u) {
if(l[u] < l[1]) return -1;
return (l[u] - l[1] + 1 + A - B - 1) / (A - B) + 1;
}
void main() {
priority_queue<pii, vector<pii>, greater<pii>> Q;
int now = -1;
memset(vis + 1, false, sizeof(bool) * n);
memset(ok + 1, false, sizeof(bool) * n);
Q.push({-1, 1}), vis[1] = true;
while(!Q.empty()) {
auto u = Q.top(); Q.pop();
if(u.first > now + 1) break;
ok[u.second] = true, now ++;
for(int i = h[u.second]; i != -1; i = ne[i]) {
int v = e[i]; if(vis[v]) continue;
vis[v] = true; Q.push({get(v), v});
}
}
for(int i = 2; i <= n; i ++)
if(!ok[i]) solver::C[i] = -1;
else solver::C[i] = n + 1, solver::Min[i] = get(i);
solver::Dijkstra();
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) {
cin >> n >> m >> A >> B;
memset(h + 1, -1, sizeof(int) * n), idx = 0;
for(int i = 1; i <= m; i ++) {
int a, b; cin >> a >> b;
add(a, b), add(b, a);
}
for(int i = 1; i <= n; i ++) cin >> l[i];
for(int i = 2; i <= n; i ++) l[i] += B;
if(A == B) solver1::main();
else if(A < B) solver2::main();
else solver3::main();
}
return 0;
}
K. Vision Test
暂时不能给你明确的答复。
L. Fenwick Tree
对每个
单租数据的时间复杂度为
code for L
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n; string str;
inline void solve() {
cin >> n >> str; str = "$" + str;
int res = 0; vector<int> C(n + 1, 0);
for(int i = 1; i <= n; i ++) if(str[i] == '1') {
if(i + (i & -i) <= n) C[i + (i & -i)] ++;
}
for(int i = 1; i <= n; i ++) {
if(str[i] == '0' && C[i] == 1) res ++;
if(str[i] == '1' && C[i] == 0) res ++;
}
cout << res << '\n';
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)