CF系列题解
Codeforces Round #783 (Div. 2)
题目
A. Direction Change
原题链接
题意
给定两个整数 n , m n,m n,m,你可以往上下左右四个方向走,但不能连续的走两个相同的方向,求从 ( 1 , 1 ) (1,1) (1,1) 到 ( n , m ) (n,m) (n,m) 的最短路。
输入格式
第一行包含一个整数
t
(
1
≤
t
≤
1
0
3
)
t (1≤t≤10^3)
t(1≤t≤103) ,表示有t组测试数据。
每个测试数据第一行包含三个整数
n
,
m
(
1
≤
n
,
m
≤
1
0
9
)
n,m (1≤n,m≤10^9)
n,m(1≤n,m≤109) 。
输出格式
输出最短路,若不能到达,输出
−
1
-1
−1。
输入样例:
6
1 1
2 1
1 3
4 2
4 6
10 5
输出样例:
0
1
-1
6
10
17
题解
思路
首先我们先不考虑无解的情况,我们假设 n > m n>m n>m,每次都先走到 ( m i n ( n , m ) , m i n ( n , m ) ) (min(n,m),min(n,m)) (min(n,m),min(n,m)),接下来分类讨论。
当
a
b
s
(
n
−
m
)
abs(n-m)
abs(n−m) 为偶数时:
此时
a
n
s
=
(
m
−
1
)
×
2
+
(
n
−
m
)
/
2
×
4
ans=(m-1)×2+(n-m)/2×4
ans=(m−1)×2+(n−m)/2×4
当
a
b
s
(
n
−
m
)
abs(n-m)
abs(n−m) 为奇数时:
此时
a
n
s
=
(
m
−
1
)
×
2
+
(
n
−
m
)
/
2
×
4
−
1
ans=(m-1)×2+(n-m)/2×4-1
ans=(m−1)×2+(n−m)/2×4−1
考虑无解情况,我们发现只要 n > 1 n>1 n>1 或者 m > 1 m>1 m>1,那么均可以用折线的方式移动从而到达终点,因此我们只需要对 1 1 1 进行特判即可。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
using i64 = long long;
void solve()
{
int n, m;
cin >> n >> m;
if (n < m) swap(n, m); // 保证 n > m
if (m == 1) {
if (n == 1) {
cout << "0\n";
} else if (n == 2) {
cout << "1\n";
} else {
cout << "-1\n";
}
return;
}
int ans = (m - 1) * 2;
int cnt = n - m;
if (cnt % 2) {
ans += cnt / 2 * 4 + 1;
} else {
ans += cnt / 2 * 4;
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
B. Social Distance
原题链接
题意
给定 m m m 个椅子排成一圈,我们有 n n n 个人且每个人都希望自己两边 a i a_i ai 个人的位置没有人,问能否满足要求。
输入格式
第一行包含一个整数
t
(
1
≤
t
≤
5
⋅
1
0
4
)
t (1≤t≤5⋅10^4)
t(1≤t≤5⋅104) ,表示有t组测试数据。
每个测试数据第一行包含两个整数
n
,
m
(
2
≤
n
≤
2
⋅
1
0
5
;
1
≤
m
≤
1
0
9
)
n,m (2≤n≤2⋅10^5; 1≤m≤10^9)
n,m(2≤n≤2⋅105;1≤m≤109)。
每个测试数据第二行包含
n
n
n 个整数
a
1
,
a
2
,
.
.
.
a
n
(
1
≤
a
i
≤
1
0
9
)
a_1, a_2, ... a_n (1≤a_i≤10^9)
a1,a2,...an(1≤ai≤109)。
n
n
n 的总和不超过
1
0
5
10^5
105。
输出格式
若能满足要求输出 YES
,否则输出 NO
。
输入样例:
6
3 2
1 1 1
2 4
1 1
2 5
2 1
3 8
1 2 1
4 12
1 2 1 3
4 19
1 2 1 3
输出样例:
NO
YES
NO
YES
NO
YES
题解
思路
贪心,我们先对 a a a 进行排序,然后从大到小枚举,每次所需要的位置数 a n s = a n s + a i + 1 ans=ans+a_i+1 ans=ans+ai+1,注意边界。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
using i64 = long long;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
sort(a.begin(), a.end());
int sum = 0;
for (int i = n - 1; i > 0; i -- ) { // 不能加到0,因为0要和n-1相邻,需要满足n-1号同学对于距离的需求
sum += a[i] + 1;
}
sum += a[n - 1] + 1;
if (sum <= m) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
C. Make it Increasing
原题链接
题意
给定一个序列 a a a, b b b 为一个全零序列,每次操作可以使得 b i = b i + a i b_i=b_i+a_i bi=bi+ai 或者 b i = b i − a i b_i=b_i-a_i bi=bi−ai,求使得 b b b 严格单调上升的最少的操作次数
输入格式
第一行包含三个整数
n
(
2
≤
n
≤
5000
)
.
n (2≤n≤5000).
n(2≤n≤5000).。
第二行包含
n
n
n 个整数
a
1
,
a
2
,
.
.
.
,
a
n
(
1
≤
a
i
≤
1
0
9
)
a_1, a_2, ..., a_n (1≤a_i≤10^9)
a1,a2,...,an(1≤ai≤109)。
输出格式
一个整数表示最小的操作次数。
输入样例:
5
1 2 3 4 5
输出样例:
4
输入样例:
7
1 2 1 2 1 2 1
输出样例:
10
输入样例:
8
1 8 2 7 3 6 4 5
输出样例:
16
题解
思路
首先我们需要确定一点,一个 b i b_i bi 若是减去 a i a_i ai,那么其必然一直做减法操作,加法亦然,因此必然会出现一个且只有一个 b t b_t bt 是既不需要加也不需要减,即 b t = 1 b_t=1 bt=1,因此我们只需要枚举 t t t 然后将 [ 1 , t − 1 ] [1,t-1] [1,t−1] 和 [ t + 1 , n ] [t+1,n] [t+1,n] 变为单调的即可。
细节见代码。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
using i64 = long long;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
int ans = 1e18;
for (int i = 0; i < n; i ++ ) {
int l = 0, r = 0;
int res = 0;
for (int j = i - 1; j >= 0; j -- ) {
int cnt = l / a[j] + 1; // 保证严格单调增
l = cnt * a[j];
res += cnt;
}
for (int j = i + 1; j < n; j ++ ) {
int cnt = r / a[j] + 1;
r = cnt * a[j];
res += cnt;
}
ans = min(ans, res);
}
cout << ans << "\n";
return 0;
}
D - Optimal Partition
原题链接
题意
输入格式
输出格式
输入样例:
5
3
1 2 -3
4
0 -2 3 -4
5
-1 -2 3 -1 -1
6
-1 2 -3 4 -5 6
7
1 -1 -1 1 -1 -1 1
输出样例:
1
2
1
6
-1
题解
思路
树状数组优化dp,人麻了,先贴个代码。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 5e5 + 10, inf = 1e9;
int n;
int a[N];
i64 s[N];
int tr[N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int v)
{
for (int i = x; i <= n; i += lowbit(i)) tr[i] = max(tr[i], v);
}
int query(int x)
{
int res = -inf;
for (int i = x; i > 0; i -= lowbit(i)) res = max(res, tr[i]);
return res;
}
void init()
{
for (int i = 0; i <= n; i ++ ) tr[i] = -inf;
}
void solve()
{
cin >> n;
init();
vector<pair<i64, int>> v;
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
s[i] = s[i - 1] + a[i];
v.push_back({s[i], -i});
}
sort(v.begin(), v.end());
vector<int> pos(n + 1);
for (int i = 0; i < n; i ++ ) pos[-v[i].second] = i + 1;
vector<int> dp(n + 1);
for (int i = 1; i <= n; i ++ ) {
dp[i] = dp[i - 1] + (a[i] < 0 ? -1 : a[i] > 0 ? 1 : 0);
dp[i] = max(dp[i], query(pos[i]) + i);
if (s[i] > 0) dp[i] = i;
add(pos[i], dp[i] - i);
}
cout << dp[n] << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int inf = 1e9;
template <typename T>
struct BIT {
const int n;
vector<T> tr;
BIT(int n) : n(n), tr(n + 1, -inf) {}
int lowbit(int x) {
return x & -x;
}
void add(int x, T v) {
for (int i = x + 1; i <= n; i += lowbit(i)) tr[i] = max(tr[i], v);
}
T query(int x) {
T res = -inf;
for (int i = x; i > 0; i -= lowbit(i)) res = max(res, tr[i]);
return res;
}
};
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
vector<i64> s(n + 1);
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
auto v = s;
sort(v.begin(), v.end());
for (int i = 0; i <= n; i ++ ) s[i] = lower_bound(v.begin(), v.end(), s[i]) - v.begin();
BIT<int> B(n + 1);
vector<int> dp(n + 1);
for (int i = 1; i <= n; i ++ ) {
B.add(s[i - 1], dp[i - 1] - (i - 1));
dp[i] = max(dp[i - 1] + (a[i] < 0 ? -1 : 0), B.query(s[i]) + i);
}
cout << dp[n] << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}