T1:Nine
当 \(A+1 = B\) 且 \(A \% 3 = 1\) 时,说明 \(A\) 和 \(B\) 相邻
代码实现
a, b = map(int, input().split())
if a+1 == b and a%3 != 0:
print('Yes')
else:
print('No')
T2:Rotate
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n;
cin >> n;
vector<string> a(n);
rep(i, n) cin >> a[i];
vector<P> ps;
rep(i, n-1) ps.emplace_back(0, i);
rep(i, n-1) ps.emplace_back(i, n-1);
rep(i, n-1) ps.emplace_back(n-1, n-1-i);
rep(i, n-1) ps.emplace_back(n-1-i, 0);
auto b = a;
int m = ps.size();
rep(mi, m) {
auto [i, j] = ps[mi];
auto [ni, nj] = ps[(mi+1)%m];
b[ni][nj] = a[i][j];
}
rep(i, n) cout << b[i] << '\n';
return 0;
}
T3:Medicine
对于第 \(i\) 天所吃的药的总和为 \(s_i\),我们可以将相同的 \(s_i\) 划分为一组
比如样例1:
1: 19
2: 10
3: 5
4: 5
5: 3
6: 3
7: 0
可以将 \(5, 5\) 划分为一组,\(3, 3\) 划分到一组,其他数单独为一组
考虑对序列 \((a_i, s_i)\) 按 \(a_i\) 的大小进行升序排序
可以发现,如果 \(s_{i+1} \neq s_i\),那么 \(s_{i+1}\) 一定在新的组中,我们只需考虑同一个 \(s_i\) 第一次出现的位置即可
于是,我们可以仅对序列 \((a_i, b_i)\) 按 \(a_i\) 的大小进行升序排序
在我们扫描序列 \((a_i, b_i)\) 时,可以通过当前组的 \(s\) 减去 \(b_i\) 就能得到新的一组的 \(s\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
int main() {
int n, k;
cin >> n >> k;
vector<P> ps;
ll tot = 0;
rep(i, n) {
int a, b;
cin >> a >> b;
ps.emplace_back(a, b);
tot += b;
}
if (tot <= k) {
puts("1");
return 0;
}
sort(ps.begin(), ps.end());
for (auto [a, b] : ps) {
tot -= b;
if (tot <= k) {
cout << a+1 << '\n';
return 0;
}
}
return 0;
}
也可以用 std::map<int, int> 来实现
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
int main() {
int n, k;
cin >> n >> k;
map<int, ll> mp;
ll tot = 0;
rep(i, n) {
int a, b;
cin >> a >> b;
mp[a] += b;
tot += b;
}
if (tot <= k) {
puts("1");
return 0;
}
for (auto [a, b] : mp) {
tot -= b;
if (tot <= k) {
cout << a+1 << '\n';
return 0;
}
}
return 0;
}
T4:Add One Edge
跑两遍 bfs 分别求出从点 \(1\) 和点 \(N_1+N_2\) 开始的最长路
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
int main() {
int n1, n2, m;
cin >> n1 >> n2 >> m;
int n = n1+n2;
vector<vector<int>> to(n);
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
to[b].push_back(a);
}
vector<int> d1, dt;
auto bfs = [&](int sv) {
const int INF = 1001001001;
vector<int> dist(n, INF);
queue<int> q;
q.push(sv); dist[sv] = 0;
while (q.size()) {
int v = q.front(); q.pop();
for (int u : to[v]) {
if (dist[u] != INF) continue;
dist[u] = dist[v]+1;
q.push(u);
}
}
return dist;
};
d1 = bfs(0);
dt = bfs(n-1);
int ans = 1;
{
int mx = 0;
rep(i, n1) mx = max(mx, d1[i]);
ans += mx;
}
{
int mx = 0;
rep(i, n2) mx = max(mx, dt[n1+i]);
ans += mx;
}
cout << ans << '\n';
return 0;
}
T5:Family and Insurance
注意到,假设点 \(i\) 的父节点为 \(x\),同时 \(x\) 的保险补偿对象是他的子孙 \(y\) 代人,那么点 \(i\) 除了保险对象以外,还需将保险补偿交给他的子孙 \(y-1\) 代人,所以要将 \(y-1\) 挂在点 \(i\) 上
记 dp[v] 表示点 \(v\) 的保险补偿对象是他的后几代人
然后自顶向下转移即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> to(n);
for (int i = 1; i < n; ++i) {
int p;
cin >> p;
--p;
to[p].push_back(i);
}
vector<int> d(n, -1);
rep(i, m) {
int x, y;
cin >> x >> y;
--x;
d[x] = max(d[x], y);
}
auto dfs = [&](auto f, int v) -> void {
for (int u : to[v]) {
d[u] = max(d[u], d[v]-1);
f(f, u);
}
};
dfs(dfs, 0);
int ans = 0;
rep(i, n) if (d[i] != -1) ans++;
cout << ans << '\n';
return 0;
}
T6:Box in Box
首先,我们可以对 \((h_i, w_i, d_i)\) 排序使得 \(h_i < w_i < d_i\)
然后接下来就是扫描线的工作了
具体地,我们可以先将 \((h_i, w_i, d_i)\) 按 \(h_i\) 的大小做升序排序,再枚举 \((h_i, w_i, d_i)\),调查之前有没有 \((h_j, w_j, d_j)\) 满足 \(w_j < w_i\) 且 \(d_j < d_i\),此时我们可以不管 \(h_i\),那么这个问题就是个二维偏序问题:我们需要对 \(w_i\) 进行离散化并作为 \(x\) 坐标,将 \(d_i\) 作为 \(y\) 坐标,然后调查当前 \(x\) 坐标左边的 \(y\) 坐标的最小值是否小于当前的 \(y\) 坐标即可,可以用线段树来维护
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
// Coodinate Compression
template<typename T=int>
struct CC {
bool initialized;
vector<T> xs;
CC(): initialized(false) {}
void add(T x) { xs.push_back(x);}
void init() {
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end());
initialized = true;
}
int operator()(T x) {
if (!initialized) init();
return upper_bound(xs.begin(), xs.end(), x) - xs.begin() - 1;
}
T operator[](int i) {
if (!initialized) init();
return xs[i];
}
int size() {
if (!initialized) init();
return xs.size();
}
};
const int INF = 1001001001;
int op(int a, int b) { return min(a, b); }
int e() { return INF; }
int main() {
int n;
cin >> n;
map<int, vector<P>> ps;
CC bs;
rep(i, n) {
vector<int> a(3);
rep(j, 3) cin >> a[j];
sort(a.begin(), a.end());
ps[a[0]].emplace_back(a[1], a[2]);
bs.add(a[1]);
}
segtree<int, op, e> t(bs.size());
for (auto [a, bc] : ps) {
for (auto [b, c] : bc) {
b = bs(b);
if (t.prod(0, b) < c) {
puts("Yes");
return 0;
}
}
for (auto [b, c] : bc) {
b = bs(b);
t.set(b, min(c, t.get(b)));
}
}
puts("No");
return 0;
}
T7: Ban Permutation
注意到这里的 \(X\) 比较小,所以可以考虑容斥
只需遍历 \(\{1, 2, \cdots, N\}\) 的所有子集,将每个子集对应的以下的值加起来即可:
- 对于 \(S\) 中的每个 \(i\) 都满足 \(|P_i-i| < X\) 的排列 \(P\) 的个数 \(\times ~ (-1)^{|S|}\)
下面考虑子集 \(S\) 中的每个 \(i\) 都满足 \(|P_i-i| < X\) 的排列 \(P\) 的个数:
记 dp[i][j][s] 表示在 \(P\) 的前 \(i\) 项中先确定了 \(j\) 个数,其中介于 \(i-X \sim i+X\) 之间的以 \(2\) 进制表示的整数集合为 \(s\)
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using mint = modint998244353;
using ll = long long;
using P = pair<int, int>;
int main() {
int n, x;
cin >> n >> x;
--x;
int w = x*2, w2 = 1<<w;
vector dp(1, vector<mint>(w2));
dp[0][(1<<x)-1] = 1;
rep(i, n) {
vector p(i+2, vector<mint>(w2));
swap(dp, p);
rep(j, i+1)rep(s, w2) {
mint now = p[j][s];
if (now == 0) continue;
dp[j][s>>1] += now;
rep(k, w+1) if (~s>>k&1) {
dp[j+1][(s|1<<k)>>1] += now;
}
}
}
vector<mint> fact(n+1, 1);
rep(i, n) fact[i+1] = fact[i]*(i+1);
mint ans;
rep(j, n+1)rep(s, w2) {
mint now = dp[j][s];
if (now == 0) continue;
if (s >= (1<<x)) continue;
ans += now*fact[n-j]*mint(-1).pow(j);
}
cout << ans.val() << '\n';
return 0;
}
浙公网安备 33010602011771号