T1:Weekly Records
模拟
代码实现
n = int(input())
a = list(map(int, input().split()))
ans = [0]*n
for i in range(n):
for j in range(i*7, (i+1)*7):
ans[i] += a[j]
for x in ans:
print(x, end=' ')
T2:racecar
模拟
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
bool isPalindrome(string s) {
string t = s;
reverse(t.begin(), t.end());
return s == t;
}
int main() {
int n;
cin >> n;
vector<string> s(n);
rep(i, n) cin >> s[i];
rep(i, n)rep(j, n) {
if (i == j) continue;
string t = s[i]+s[j];
if (isPalindrome(t)) {
puts("Yes");
return 0;
}
}
puts("No");
return 0;
}
T3:Ideal Sheet
暴力枚举两张图的摆放位置即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
struct Sheet {
int h, w;
vector<string> s;
void input() {
cin >> h >> w;
s = vector<string>(h);
rep(i, h) cin >> s[i];
}
void clear() {
rep(i, h)rep(j, w) s[i][j] = '.';
}
bool copy(Sheet a, int di, int dj) {
rep(i, a.h)rep(j, a.w) {
if (a.s[i][j] == '.') continue;
int ni = i+di, nj = j+dj;
if (ni < 0 or ni >= h or nj < 0 or nj >= w) return false;
s[ni][nj] = a.s[i][j];
}
return true;
}
};
int main() {
Sheet a, b, x;
a.input();
b.input();
x.input();
for (int ai = -a.h; ai < x.h; ++ai) {
for (int aj = -a.w; aj < x.w; ++aj) {
for (int bi = -b.h; bi < x.h; ++bi) {
for (int bj = -b.w; bj < x.w; ++bj) {
Sheet y = x;
y.clear();
if (!y.copy(a, ai, aj)) continue;
if (!y.copy(b, bi, bj)) continue;
if (x.s == y.s) {
puts("Yes");
return 0;
}
}
}
}
}
puts("No");
return 0;
}
T4:Mismatched Parentheses
可以根据 (
的出现位置将字符串进行分割,即每个分割子串以 (
的前一个字符结尾,可以用一个栈来维护所有的分割子串。
然后扫描字符串 \(s\),如果遇到 )
,此时如果栈里有元素的话,就弹出栈顶元素。
时间复杂度为 \(O(n)\)
代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
string s;
cin >> n >> s;
vector<string> st;
st.push_back("");
for (char c : s) {
if (c == '(') {
st.push_back("(");
}
else if (c == ')') {
if (st.size() == 1) st.back() += c;
else st.pop_back();
}
else {
st.back() += c;
}
}
string ans;
for (string t : st) ans += t;
cout << ans << '\n';
return 0;
}
T5:Distinct Adjacent
不妨固定分配给第一个人的数,然后进行 \(dp\)
记 dp[i][0/1]
表示在前 \(i\) 个人中给最后一个人分配和第一个人相同(不同)的数的合法方案数
最后的答案为 \(dp[n][1]*m\)
时间复杂度为 \(\mathcal{O}(n)\)
代码实现
#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;
int main() {
int n, m;
cin >> n >> m;
vector dp(n, vector<mint>(2));
dp[0][0] = 1;
for (int i = 1; i < n; ++i) {
dp[i][0] = dp[i-1][1];
dp[i][1] = dp[i-1][0]*(m-1);
dp[i][1] += dp[i-1][1]*(m-2);
}
mint ans = dp[n-1][1]*m;
cout << ans.val() << '\n';
return 0;
}
T6:Virus 2
对每个点 \(i\) 维护好它的感染日 \(d_i\) 以及感染日前一天的所有被感染点到点 \(i\) 的最短距离 \(e_i\),然后跑 \(\operatorname{Dijkstra}\)
问题是传播要延迟到第二天以后,但如果在给定 \(d\) 和 \(w\) 的前提下,提前预处理出在 \(d\) 天以后 \(X_j \geqslant w\) 的最早的一天,就能及时找到它。
可以用倍增或者线段树上二分来优化
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
using PP = pair<P, int>;
inline void chmax(int& x, int y) { if (x < y) x = y; }
struct Edge {
int to, w;
Edge(int to=0, int w=0): to(to), w(w) {}
};
int main() {
int n, m;
cin >> n >> m;
vector<vector<Edge>> g(n);
rep(i, m) {
int a, b, w;
cin >> a >> b >> w;
--a; --b;
g[a].emplace_back(b, w);
g[b].emplace_back(a, w);
}
const int INF = 1001001001;
vector<P> dist(n, P(INF, INF));
priority_queue<PP, vector<PP>, greater<PP>> q;
auto push = [&](int v, P x) {
if (dist[v] <= x) return;
dist[v] = x;
q.emplace(x, v);
};
{
int k;
cin >> k;
rep(i, k) {
int a;
cin >> a;
--a;
push(a, P(-1, 0));
}
}
int D;
cin >> D;
vector<int> x(D);
rep(i, D) cin >> x[i];
const int K = 19;
vector dp(K, vector<int>(D, -INF));
rep(i, D) dp[0][i] = x[i];
rep(i, K-1) {
dp[i+1] = dp[i];
rep(j, D) {
int nj = j+(1<<i);
if (nj >= D) break;
chmax(dp[i+1][j], dp[i][nj]);
}
}
auto f = [&](P p, int w) {
auto [i, j] = p;
if (i != -1 and j+w <= x[i]) return P(i, j+w);
int ni = i+1;
// while (ni < d and x[ni] < w) ni++;
for (int k = K-1; k >= 0; --k) {
if (w > dp[k][ni]) ni += 1<<k;
if (ni >= D) return P(INF, INF);
}
return P(ni, w);
};
while (q.size()) {
auto [p, v] = q.top(); q.pop();
if (dist[v] != p) continue;
for (auto& e : g[v]) {
push(e.to, f(p, e.w));
}
}
rep(i, n) {
int ans = dist[i].first;
if (ans == INF) ans = -1;
else ans++;
cout << ans << '\n';
}
return 0;
}
T7:Approximate Equalization
由于在最终的数组 \(a\) 中任意两数之差的绝对值不超过 \(1\),所以最终的数组 \(a\) 中至多有两种数,不妨记为 \(x\) 和 \(x+1\)。
注意到两种操作不会影响到 \(\sum a_i\),所以我们可以求出 \(x\) 和 \(x+1\) 具体的值以及对应的出现次数,即 \(x\) 和 \(x+1\) 分别为 \(\lfloor\frac{\sum a_i}{n}\rfloor\) 和 \(\lfloor\frac{\sum a_i}{n}\rfloor +1\)。
记 dp[i][j]
表示在前 \(i\) 个数中有 \(j\) 个数被变成了 \(x+1\) 的最小操作次数
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
inline void chmin(ll& a, ll b) { if (a > b) a = b; }
int main() {
int n;
cin >> n;
vector<ll> a(n);
rep(i, n) cin >> a[i];
rep(i, n) a[i] += 1e9;
ll s = reduce(a.begin(), a.end());
rep(i, n) a[i] -= s/n;
s %= n;
rep(i, n-1) a[i+1] += a[i];
const ll INF = 1e18;
vector<ll> dp(s+1, INF);
dp[0] = 0;
rep(i, n) {
vector<ll> p(s+1, INF); swap(dp, p);
rep(j, s+1) {
chmin(dp[j], p[j]);
if (j+1 <= s) chmin(dp[j+1], p[j]);
}
rep(j, s+1) dp[j] += abs(a[i]-j);
}
cout << dp[s] << '\n';
return 0;
}