A. Letter Home
要么先走到左侧,要么走到右侧,然后整行走了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
int n, m;
cin >> n >> m;
vector<int> x(n + 1);
for (int i = 1; i <= n; i++) {
cin >> x[i];
}
int ans = min(abs(m - x[1]), abs(x[n] - m)) + x[n] - x[1];
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
B. Above the Clouds
考虑 b 只有一个字符,如果这个字符出现次数大于 2,那么一定 Yes。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
int n;
string s;
cin >> n >> s;
vector<int> cnt(26, 0);
for (char c : s) {
cnt[c - 'a']++;
}
for (int i = 1; i < n - 1; i++) {
if (cnt[s[i] - 'a'] > 1) {
cout << "YES" << endl;
return;
}
}
cout << "NO" << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
C. Those Who Are With Us
可以发现答案只可能是 mx,或 mx - 1。
统计每行每列中的 mx 个数,遍历每个元素,看行列上有多少个 mx,如果这个元素本身是 mx, 那么会多算一个,要减去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
int n, m;
cin >> n >> m;
int mx = 0;
map<int, int> cnt;
map<int, int> row, col;
vector<vector<int>> a(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int x;
cin >> x;
mx = max(mx, x);
cnt[x]++;
a[i][j] = x;
}
}
int ans = mx;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if(a[i][j] == mx) row[i]++, col[j]++;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int tmp = row[i] + col[j];
if (a[i][j] == mx) tmp--;
if (tmp == cnt[mx]) {
cout << ans - 1 << endl;
return;
}
}
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
D. 1709
可以观察到,数组极小,仅 40,暴力来搞即可,对两个数组冒泡,再从头到尾判断上面不能比下面大即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
int n;
cin >> n;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
vector<pair<int, int>> ans;
for (int i = 1; i <= n; i++) {
for (int j = 2; j <= n; j++) {
if (a[j - 1] > a[j]) {
swap(a[j - 1], a[j]);
ans.push_back({1, j - 1});
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 2; j <= n; j++) {
if (b[j - 1] > b[j]) {
swap(b[j - 1], b[j]);
ans.push_back({2, j - 1});
}
}
}
for (int i = 1; i <= n; i++) {
if (a[i] > b[i]) {
ans.push_back({3, i});
}
}
cout << ans.size() << endl;
for (auto &p : ans) {
cout << p.first << " " << p.second << endl;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
数位 DP,从左往右看两个数。
有两种特殊情况:
- 左侧片段和 l 相同,当前这一位只能 >= $l_i$
- 左侧片段和 r 相同,当前这一位只能 <= $r_i$
其余情况能任意取,保证最小即可。
具体可参考代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
string l, r;
cin >> l >> r;
int n = l.size();
vector<vector<int>> f(2, vector<int>(2, 0)), nf(2, vector<int>(2, 0)); //优化空间,只开两层。
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) f[i][j] = nf[i][j] = 1e9;
}
f[1][1] = 0;
for (int i = 0; i < n; i++) {
for (int a = 0; a < 2; ++a)
for (int b = 0; b < 2; ++b) nf[a][b] = 1e9;
int dl = l[i] - '0', dr = r[i] - '0';
for (int a = 0; a < 2; ++a) {
for (int b = 0; b < 2; ++b) {
if (f[a][b] < 1e9) {
int lo = a ? dl : 0; //如果前面和 l 相同,则只能取大于等于 l 当前位
int hi = b ? dr : 9; //如果前面和 r 相同,则只能取小于等于 r 当前位
for (int d = lo; d <= hi; d++) {
int c = (d == dl) + (d == dr); //当前代价
int na = a && (d == dl); //前面相同,同时这一位也相同,保留状态
int nb = b && (d == dr);
nf[na][nb] = min(nf[na][nb], f[a][b] + c); //取最优
}
}
}
}
f = nf;
}
int ans = min({f[0][0], f[0][1], f[1][0], f[1][1]});
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
F. Yamakasi
统计前缀和出现次数,查找当前前缀和 - s 的出现次数,以大于 x 的为分界线,遇到就重置当前统计量。
以函数实现,查找 x 和 x - 1 相减即只剩下 x 的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
ll n, s, x;
cin >> n >> s >> x;
vector<ll> a(n + 10), pre(n + 10);
for (int i = 1; i <= n; i++) {
cin >> a[i];
pre[i] = pre[i - 1] + a[i];
}
ll ans = 0;
auto calc = [&](ll x) {
map<ll, int> cnt;
cnt[0] = 1;
ll res = 0;
for (int i = 1; i <= n; i++) {
if (a[i] > x) {
cnt.clear();
}
if (cnt.count(pre[i] - s)) {
res += cnt[pre[i] - s];
}
cnt[pre[i]]++;
}
return res;
};
ans = calc(x) - calc(x - 1);
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
G. Gangsta
设 1 出现次数为 a,0 出现次数为 b,那么 $\max(a, b) = \frac{a + b + |a - b|}{2}$
即 $f(s_{l..r}) = \frac{(c_0(l, r) + c_1(l, r)) + |c_1(l, r) - c_0(l, r)|}{2}$
现在,总和 $S$ 可以被分解为两部分:
$S = \sum_{1 \le l \le r \le n} \frac{(c_0(l, r) + c_1(l, r)) + |c_1(l, r) - c_0(l, r)|}{2}$
$S = \frac{1}{2} \left( \sum_{1 \le l \le r \le n} (c_0(l, r) + c_1(l, r)) + \sum_{1 \le l \le r \le n} |c_1(l, r) - c_0(l, r)| \right)$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
int n;
string s;
cin >> n >> s;
vector<ll> p(n + 1, 0);
for (int i = 1; i <= n; i++) {
if (s[i - 1] == '1') p[i] = p[i - 1] + 1;
else p[i] = p[i - 1] - 1;
}
sort(p.begin(), p.end());
ll ans = 0;
ll sum = 0, tot = 0;
for (int i = 0; i <= n; i++) {
tot += i * p[i] - sum;
sum += p[i];
}
ll total = 1ll * n * (n + 1) * (n + 2) / 6;
ans = (total + tot) / 2;
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|
H. Ice Baby
考虑维护 dp, $dp_i$ 表示长度为 i 时,末尾的数的最小值。
dp 数组一定是不递减的,在线考虑 $l_i, r_i$ 加入时对 dp 的影响。
$$
dp'_j =
\begin{cases}
dp_j & \text{if } R_i < dp_{j-1} \\
& \text{(无法用 } i \text{ 延续长度为 } j-1 \text{ 的最优序列)} \\
\\
\min(dp_j, \max(L_i, dp_{j-1})) & \text{if } L_i < dp_j \text{ and } R_i \ge dp_{j-1} \\
& \text{(用 } i \text{ 延续序列是可能的,且可能优化 } dp_j \text{)} \\
\\
dp_j & \text{if } L_i \ge dp_j \\
& \text{(用 } i \text{ 延续序列无法得到比 } dp_j \text{ 更优的结果)}
\end{cases}
$$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 7, mod = 1e9 + 7;
void solve() {
int n;
cin >> n;
multiset<int> s;
// s.insert(0);
for (int i = 1; i <= n; i++) {
int l, r;
cin >> l >> r;
auto pos = s.upper_bound(r);
s.insert(l);
if (pos != s.end()) s.erase(pos);
cout << s.size() << " ";
}
cout << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
|