A. Pairing
模拟
代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> a(4);
cin >> a[0] >> a[1] >> a[2] >> a[3];
ranges::sort(a);
if (a[0] == a[1] and a[2] == a[3]) {
puts("2");
}
else if (a[0] == a[1]) {
puts("1");
}
else if (a[1] == a[2]) {
puts("1");
}
else if (a[2] == a[3]) {
puts("1");
}
else puts("0");
return 0;
}
B. Garbage Collection
答案为 \(\left\lceil\dfrac{d-r_t}{q_t}\right\rceil \cdot q_t + r_t\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> q(n), r(n);
rep(i, n) cin >> q[i] >> r[i];
int Q;
cin >> Q;
rep(Qi, Q) {
int t, d;
cin >> t >> d;
--t;
d -= r[t];
int ans = (d+q[t]-1)/q[t]*q[t] + r[t];
cout << ans << '\n';
}
return 0;
}
C. Repeating
用 map
来维护每种数上一次出现的位置
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
map<int, int> last;
vector<int> ans(n);
rep(i, n) {
if (last.contains(a[i])) ans[i] = last[a[i]];
else ans[i] = -1;
last[a[i]] = i+1;
}
rep(i, n) cout << ans[i] << ' ';
return 0;
}
D. Count Simple Paths
\(\operatorname{dfs}\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};
int main() {
int h, w, k;
cin >> h >> w >> k;
vector<string> s(h);
rep(i, h) cin >> s[i];
auto dfs = [&](auto& f, int i, int j, int k) -> int {
if (k == 0) return 1;
s[i][j] = '*';
int res = 0;
rep(v, 4) {
int ni = i+di[v], nj = j+dj[v];
if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
if (s[ni][nj] != '.') continue;
res += f(f, ni, nj, k-1);
}
s[i][j] = '.';
return res;
};
int ans = 0;
rep(si, h)rep(sj, w) {
if (s[si][sj] == '#') continue;
ans += dfs(dfs, si, sj, k);
}
cout << ans << '\n';
return 0;
}
E. Mod Sigma Problem
记 \(\displaystyle S_i = \sum_{k = 0}^{i-1} A_k\)
\(\displaystyle \sum_{l \leqslant i < r} A_i = S_r - S_l\)
注意到 \((S_r - S_l) \bmod M = (S_r \bmod M - S_l \bmod M) \bmod M\)
下面默认之后的 \(S_i\) 都是对 \(M\) 取模后的
显然 \(S_i\) 的取值范围为 \([0, M-1]\)
若 \(S_r - S_l < 0\),则 \((S_r - S_l) \bmod M = S_r - S_l + M\)
若 \(S_r - S_l \geqslant 0\),则 \((S_r - S_l) \bmod M = S_r - S_l\)
于是,\(\displaystyle \sum_{l < r} (S_l - S_r) \bmod M = \sum_{l < r} (S_r - S_l) + \sum_{l < r\\S_l > S_r} M\)
其中 \(\displaystyle \sum_{l < r} (S_r - S_l) + \sum_{l < r\\S_l > S_r} M\) 等于满足 \(S_l > S_l\) 的二元组 \((l, r)\) 的个数 \(\times M\)
\(\displaystyle \sum_{l < r} (S_r - S_l) = \displaystyle \left(\sum_{l < r} S_r\right) - \left(\sum_{l < r} S_l\right) = \sum_r S_r \times r - \sum_l S_l \times (N-l)\)
上面提到的满足 \(S_l > S_r\) 的二元组 \((l, r)\) 的个数其实就是逆序数
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
rep(i, n) cin >> a[i];
vector<ll> s(n+1);
rep(i, n) s[i+1] = s[i]+a[i];
n = s.size();
rep(i, n) s[i] %= m;
ll ans = 0;
rep(r, n) ans += s[r]*r;
rep(l, n) ans -= s[l]*(n-l-1);
ll cnt = 0;
fenwick_tree<int> t(m);
rep(i, n) {
cnt += t.sum(s[i]+1, m);
t.add(s[i], 1);
}
ans += cnt*m;
cout << ans << '\n';
return 0;
}
F. Add One Edge 2
本质上是统计有多少个点对满足除了这两个点的度数以外位于这两个点的路径上的其他点的度数都是 \(3\)
记 dp[v]
表示在点 \(v\) 为根的子树中从点 \(v\) 开始的类似 33...32
的路径数
答案有两种情况:
一种是当点 \(v\) 的度数是 \(2\) 时,对答案的贡献就是 \(\sum dp[u]\),其中点 \(u\) 是点 \(v\) 的儿子节点
另一种是当点 \(v\) 的度数是 \(3\) 时,对答案的贡献就是以点 \(v\) 为 \(lca\) 的两边都是 33...2
形式的路径数
注意第一种会将 22
统计进去,所以最后要减去这一部分的贡献才是正确答案
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<vector<int>> to(n);
rep(i, n-1) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
to[b].push_back(a);
}
vector<int> deg(n);
rep(i, n) deg[i] = to[i].size();
ll ans = 0;
vector<ll> dp(n);
auto dfs = [&](auto& f, int v, int p=-1) -> void {
for (int u : to[v]) {
if (u == p) continue;
f(f, u, v);
if (deg[v] == 3) {
ans += dp[v]*dp[u];
}
if (deg[v] == 3) dp[v] += dp[u];
if (deg[v] == 2) {
ans += dp[u];
if (deg[u] == 2) ans--;
}
}
if (deg[v] == 2) dp[v]++;
};
dfs(dfs, 0);
cout << ans << '\n';
return 0;
}
G. Everlasting LIDS
性质1:
一个 \((1, 2, \cdots, n)\) 的排列 \(X\) 和一对相同形状的标准杨表是一一对应的
定义 \(P_X\) 为杨表 \((\cdots (x_1 \gets x_2) \gets x_3 \cdots) \gets x_1\)
性质2:
\(P_X\) 中第一行长度即为排列 \(X\) 的 \(\operatorname{LIS}\) 长度
性质3:
\(P_X\) 中第一列长度即为排列 \(X\) 的 \(\operatorname{LDS}\) 长度
定义 \(Q_X\) 为记录表,即在对 \(P_X\) 插入 \(x_i\) 时将下标的 \(i\) 插入相应位置并维持 \(Q_X\) 和 \(P_X\) 的形状完全相同。显然,\(Q_X\) 也是一个杨表
回到原题,只需暴力dp求 \(P_X\) 的方案数,而 \(Q_X\) 只需套钩长公式即可