AtCoder Beginner Contest 235 题解 A - F
A - Rotate
枚举; 或者观察发现乘以 \(111\)
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
int a = (int)s[0] - '0' + s[1] - '0' + s[2] - '0';
cout << a * 111 << "\n";
}
B - Climbing Takahashi
模拟
#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
const int maxn = 1e6 + 5;
int h[maxn];
int main() {
int n;
cin >> n;
inc(i, 1, n) cin >> h[i];
inc(i, 1, n) {
if(h[i] >= h[i + 1]) {
cout << h[i];
break;
}
}
}
C - The Kth Time Query
学会用 map
#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
int main() {
int n, q;
cin >> n >> q;
map<int, vector<int> > mp;
inc(i, 1, n) {
int x;
cin >> x;
mp[x].push_back(i);
}
inc(i, 1, q) {
int x, k;
cin >> x >> k;
if (mp[x].size() < k)
cout << "-1\n";
else
cout << mp[x][k - 1] << "\n";
}
}
D - Multiply and Rotate
典型的一维 DP
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6 + 5;
int dp[maxn];
int main() {
int a, n;
cin >> a >> n;
queue<int> que;
que.push(1);
dp[1] = 1;
while (que.size()) {
int q = que.front();
que.pop();
ll p = 1LL * q * a;
if (p < 1000000) {
if (!dp[p]) {
dp[p] = dp[q] + 1;
que.push(p);
}
}
if (q % 10 && q >= 10) {
int p = q / 10 + (q % 10) * (int)(pow(10, (int)log10(q)));
if (!dp[p]) {
dp[p] = dp[q] + 1;
que.push(p);
}
}
}
cout << dp[n] - 1 << "\n";
}
E - MST + 1
Kruskal 算法, 把询问和树边一起排序
#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
const int maxn = 1e6 + 5;
struct edge {
int u, v, c, f;
bool operator<(const edge& o) { return c < o.c; }
} e[maxn];
int par[maxn];
int find(int x) {
if (x == par[x])
return x;
return par[x] = find(par[x]);
}
bool same(int x, int y) {
return find(x) == find(y);
}
void unite(int x, int y) {
if (!same(x, y))
par[find(x)] = find(y);
}
int main() {
int n, m, q;
cin >> n >> m >> q;
inc(i, 0, m - 1) {
int u, v, c;
cin >> u >> v >> c;
e[i] = {u, v, c, 0};
}
inc(i, 1, q) {
int u, v, c;
cin >> u >> v >> c;
e[m + i - 1] = {u, v, c, i};
}
sort(e, e + m + q);
inc(i, 1, n) par[i] = i;
vector<int> res(q + 1);
inc(i, 0, m + q - 1) {
if (!e[i].f) {
unite(e[i].u, e[i].v);
} else {
if (!same(e[i].u, e[i].v))
res[e[i].f] = 1;
}
}
inc(i, 1, q) if (res[i]) cout << "Yes\n";
else cout << "No\n";
}
F - Variety of Digits
题意: 给定 \(N\leq 10^{10^4}\), \(M\) 个 \(0\leq C_i<10\), 求所有 \(x<N\) 且数位包含所有 \(C_i\) 的 \(x\) 之和, 模 \(998244353\).
比较自然想到状压+数位 DP, 不过有点不好写.
\(dpc[S]:\) 二进制位包含 \(S\) 集合的数字个数
\(dps[S]:\) 二进制位包含 \(S\) 集合的数字之和
数位 DP 里的 limit, 意思是前缀是否与最大值的一致. 我们转移分三类
no-limit 转移到 no-limit, 当前位取 \([0,9]]\)
limit 转移到 no-limit, 当前位取 \([0,a[i]-1]\)
limit 转移到 limit, 其实只更新一个值
注意前导0不计入0的出现, 要额外处理.
#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
#define ll long long
const int maxn = 1e6 + 5;
const int mod = 998244353;
const int S = 1 << 10;
int a[maxn];
ll fac[maxn];
int main() {
string s;
int m;
cin >> s >> m;
int n = s.size();
inc(i, 1, n) a[i] = s[i - 1] - '0';
int C = 0;
inc(i, 1, m) {
int x;
cin >> x;
C |= 1 << x;
}
fac[n] = 1;
for (int i = n - 1; i >= 1; i--)
fac[i] = fac[i + 1] * 10 % mod;
vector<ll> dpc(S), dps(S);
int pre_or = 0;
ll pre_sum = 0;
inc(i, 1, n) {
vector<ll> ndpc(S), ndps(S);
// positive:
// no-limit -> no-limit
inc(j, 1, S - 1) inc(k, 0, 9) {
ndpc[j | 1 << k] += dpc[j];
ndps[j | 1 << k] += dps[j] + k * fac[i] % mod * dpc[j] % mod;
}
// limit -> no-limit
if (pre_or) {
inc(j, 0, a[i] - 1) {
ndpc[pre_or | 1 << j] += 1;
ndps[pre_or | 1 << j] += pre_sum + j * fac[i] % mod;
}
}
// limit update
pre_or |= 1 << a[i];
pre_sum = (pre_sum + a[i] * fac[i]) % mod;
// zero:
if (i == 1) {
inc(j, 1, a[i] - 1) {
ndpc[1 << j] += 1;
ndps[1 << j] += j * fac[i] % mod;
}
} else {
inc(j, 1, 9) {
ndpc[1 << j] += 1;
ndps[1 << j] += j * fac[i] % mod;
}
}
for (ll& e : ndpc)
e %= mod;
for (ll& e : ndps)
e %= mod;
dpc = ndpc, dps = ndps;
}
ll ans = 0;
inc(i, 0, S - 1) if ((i & C) == C) { ans += dps[i]; }
if ((pre_or & C) == C)
ans += pre_sum;
cout << ans % mod << "\n";
}