A. chmod
模拟
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
string s;
cin >> s;
int a = s[0] - '0', b = s[1] - '0', c = s[2] - '0';
if (a & 4) cout << "r";
else cout << "-";
if (a & 2) cout << "w";
else cout << "-";
if (a & 1) cout << "x";
else cout << "-";
if (b & 4) cout << "r";
else cout << "-";
if (b & 2) cout << "w";
else cout << "-";
if (b & 1) cout << "x";
else cout << "-";
if (c & 4) cout << "r";
else cout << "-";
if (c & 2) cout << "w";
else cout << "-";
if (c & 1) cout << "x";
else cout << "-";
cout << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
B. Expression Matrix
搜索,首先要尽可能多的使用符号,所以可以dp 出放置符合最多的方案。
然后搜索枚举每一个符号是加还是乘。
考虑一个剪枝优化,只有当符号所在的行或列存在两个11
的时候才能使用加,否则只能使用乘
#include <bits/stdc++.h>
using namespace std;
using i32 = int;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int INF = LLONG_MAX / 2;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector f(n + 1, vi(m + 1));
int T = 0;
vector<pii> opt;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (i == 1 or j == 1 or i == n or j == m) f[i][j] = 1;
else if (f[i - 1][j] == 1 and f[i][j - 1] == 1) f[i][j] = -(T++), opt.emplace_back(i, j);
else f[i][j] = 1;
}
vector<vi> r(n + 1);
for (int i = 1, pre; i <= n; i++) {
pre = 0;
for (int j = 1; j <= m; j++) {
if (f[i][j] == 1) pre = pre * 10 + 1;
else r[i].push_back(pre), r[i].push_back(f[i][j]), pre = 0;
}
r[i].push_back(pre);
}
vector<vi> c(m + 1);
for (int j = 1, pre; j <= m; j++) {
pre = 0;
for (int i = 1; i <= n; i++) {
if (f[i][j] == 1) pre = pre * 10 + 1;
else c[j].push_back(pre), c[j].push_back(f[i][j]), pre = 0;
}
c[j].push_back(pre);
}
vi cntR(n + 1);
for (int i = 1; i <= n; i++)
for (auto j: r[i])
if (j == 11) cntR[i]++;
vi cntC(m + 1);
for (int j = 1; j <= m; j++)
for (auto i: c[j])
if (i == 11) cntC[j]++;
vi op(T), res;
int ans = INF;
auto calc = [&](const vi &v) -> int {
vi x;
for (int i: v) {
if (i > 0) x.push_back(i);
else if (op[-i] == 0) x.push_back(-1);
}
vi y;
for (int i = 0; i < x.size(); i++) {
if (x[i] > 0) y.push_back(x[i]);
else i++, y.back() *= x[i];
}
return accumulate(y.begin(), y.end(), 0ll);
};
auto dfs = [&](auto dfs, int i) -> void {
if (i == T) {
int sum = 0;
for (int i = 1; i <= n; i++)
sum += calc(r[i]);
for (int j = 1; j <= m; j++)
sum += calc(c[j]);
if (sum < ans) ans = sum, res = op;
return;
}
auto [ix, iy] = opt[i];
if (cntR[ix] >= 2 or cntC[iy] >= 2) {
op[i] = 1;
dfs(dfs, i + 1);
}
op[i] = 0;
dfs(dfs, i + 1);
};
dfs(dfs, 0);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (f[i][j] == 1) cout << 1;
else cout << "*+"[res[-f[i][j]]];
}
cout << "\n";
}
return 0;
}
C. Seats
这到题目,把\(i\)向\(a_i\)连一条有向边,图就是内向基环树森林,其中有两种,一种是链,且最后一个点一定是空节点,此时链上所有点均可满足。另一种是内向基环树,此时只有环上的点可以满足。
所以可以用拓扑序求出链的长度,并且拓扑序没有入队的点就是环上的点。
#include <bits/stdc++.h>
using namespace std;
using i32 = int;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int, int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
int N = n * 2;
vector<vi> e(N + 1);
vi vis(N + 1), dis(N + 1), deg(N + 1);
for (int i = 1, x; i <= n; i++)
cin >> x, e[i].push_back(x), deg[x]++;
queue<int> q;
for (int i = 1; i <= N; i++)
if (deg[i] == 0) q.push(i);
while (not q.empty()) {
int x = q.front();
vis[x] = 1;
q.pop();
for (auto y: e[x]) {
dis[y] = max(dis[x], dis[x] + 1);
if (--deg[y] == 0) q.push(y);
}
}
int res = 0;
for (int i = 1; i <= N; i++) {
if (vis[i] == 0) res++;
if (e[i].empty()) res += dis[i];
}
cout << res;
return 0;
}
E. Trade Road
可以参考官方题解的证明思路,得到以下引理
不存在市场两两不相同的\(A,B,C,D\),使得商路\(\vec{AB},\vec{CD}\)同时存在
因此,最终的结果一定是有两种
- 所有商路要么从\(x\)出发,要么到达\(x\)。
- 以\(x\)为顶角的等腰三角形。
因此找到从每一个点出发的最远点,然后枚举\(x\)就好了,我这里找最远点采用了二分,而不是官解的双指针。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ldb = long double;
#define int i64
using vi = vector<int>;
int K;
int dis(int x, int y) {
return min(((x - y) % K + K) % K, ((y - x) % K + K) % K);
}
int norm(int x) {
return (x % K + K) % K;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> K >> n;
vi a(n + 1);
map<int, int> idx;
set<int> vis;
for (int i = 1; i <= n; i++) {
cin >> a[i], a[i]--, idx[a[i]] = i;
vis.insert(a[i] - K - K);
vis.insert(a[i] - K);
vis.insert(a[i]);
vis.insert(a[i] + K);
vis.insert(a[i] + K + K);
}
vector<vi> e(n + 1);
vector<map<int, int>> road(n + 1);
vi cnt(n + 1);
for (int i = 1; i <= n; i++) {
set<int> b;
int x = a[i] + K / 2;
b.insert(norm(*vis.lower_bound(x)));
b.insert(norm(*prev(vis.upper_bound(x))));
x++;
b.insert(norm(*vis.lower_bound(x)));
b.insert(norm(*prev(vis.upper_bound(x))));
int maxD = 0;
for (auto j: b)
maxD = max(maxD, dis(a[i], j));
for (auto y: b)
if (dis(a[i], y) == maxD) {
int j = idx[y];
e[i].push_back(j);
cnt[j]++;
road[i][j] = 1;
}
}
int res = 0;
for (int x = 1, ans; x <= n; x++) {
ans = cnt[x];
for (auto y: e[x])
if (road[y][x] == 0) ans++;
res = max(res, ans);
if (e[x].size() == 2) {
int y = e[x][0], z = e[x][1];
if (road[y][z])
res = max(res, 3ll);
}
}
cout << res;
return 0;
}
F. Try a try, AC is OK
与只会变小,所以序列最大值就是答案
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using vi = vector<int>;
void solve() {
int n;
cin >> n;
vi a(n);
for (auto &i: a) cin >> i;
cout << ranges::max(a) << "\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
G. Disappearing Number
一种类似数位 dp 的方法,枚举每一位的方案即可
#include <bits/stdc++.h>
using namespace std;
using i32 = int;
using i64 = long long;
#define int i64
using vi = vector<int>;
void solve() {
int n, x;
cin >> n >> x;
int pre = 1, sum = 1;
while (n) {
int y = n % 10;
if (y > x) y--;
sum += y * pre;
pre = pre * 9, n /= 10;
}
cout << sum << "\n";
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
L. Chess
考虑到在任何进制下,个位数一定是成立的,且满足条件的\(y\)个位一定是非\(0\)的。
类似 bash 博弈,如果\(x\)的个位为 0 则一定无法一步拿完,同时如果个位不为 0 ,则一定可以通过一次操作使得个位为 0。因此如果\(x\)的个位为0,则先手一定必败。所以枚举进制,找到最小\(k\)进制使得\(x\)各个位不为 0 即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int, int>;
void solve() {
i64 n;
cin >> n;
for (int i = 2;; i++)
if (n % i != 0) {
cout << i << "\n";
return;
}
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
M. Window Decoration
一个正方形的面积为 \(2\),每一个相邻的正方形会公用\(0.5\)的面积,不会出现同一块被三个及以上的正方形覆盖的情况,因此简单容斥就好了
#include <bits/stdc++.h>
using namespace std;
using i32 = int;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<pii> a(n);
for (auto &[x, y]: a)
cin >> x >> y;
sort(a.begin(), a.end());
a.resize(unique(a.begin(), a.end()) - a.begin());
double res = a.size() * 2;
for (int i = 1; i < a.size(); i++) {
auto [x, y] = a[i];
for (int j = 0; j < i; j++) {
auto [p, q] = a[j];
if (abs(x - p) + abs(y - q) == 1) res -= 0.5;
}
}
cout << fixed << setprecision(10) << res;
return 0;
}
标签:Provincial,Contest,int,vi,cin,long,2024,vector,using
From: https://www.cnblogs.com/PHarr/p/18358908