文章目录
Codeforces Round #667 (Div. 3)
A.Yet Another Two Integers Problem
题意: 给定a和b,每次可以把a+k或者a-k,
k
∈
[
1
,
10
]
k \in [1, 10]
k∈[1,10],求最少变化多少次能够使得a变成b
题解: 计算出a和b的差值,然后向上取整即可
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 2e5 + 10;
int T, n, a[N];
int main() {
cin >> T;
while(T--) {
int a, b;
cin >> a >> b;
int diff = abs(b - a);
// cout << ceil((double)diff/10)<<endl;
printf("%d\n", (int)ceil((double)diff/10));
}
return 0;
}
B.Minimum Product
题意: 给定a,b,x,y,n,每次操作可以让a–或者b–,但是a最小减到x,b最小减到y,操作次数最多为n次,问a和b经过若干次操作后,a*b的值最小是多少
题解: 假设a经过若干次后为a’,b经过若干次后为b’,则答案为res = a’*b’。要让res最小,那么a’和b’的差值要尽可能大。那么如何让差值尽可能大呢,要让小的尽可能小。但是由于x和y的限制,直接把较小的那个变化,不能达到最优值。因此,一种情况是把较小的减小,另一种是把较大的减的比原先较小的还要小。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
LL solve(LL a, LL b, LL x, LL y, LL n) {
LL delta = a - x;
if (delta <= n) return x * max((b - (n - delta)), y);
else return (a - n) * b;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int T;
cin >> T;
while(T--) {
LL a, b, x, y, n;
cin >> a >> b >> x >> y >> n;
cout << min(solve(a, b, x, y, n), solve(b, a, y, x, n)) << endl;
}
return 0;
}
C.Yet Another Array Restoration
题意: 给定等差数列中的两项,给定等差数列的项数,构造一个等差数列,且使得最大值最小
题解: 由于数字较小,都不超过50,因此直接暴力即可。暴力枚举等差数列的公差,然后每次都判断最大值,求出最小的情况即可
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
int n, m, T, y, x;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> T;
while(T--) {
cin >> n >> x >> y;
if (n == 2) {
cout << x << " " << y << endl;
continue;
}
int res_d = 0, res_mn = 10000;
for (int i = 1; i <= 50; ++i) {
if ((y - x) % i) continue;
int sum = 2;
sum += (y - x) / i - 1;
if (sum > n) continue;
int remain = n - sum;
remain -= min(x / i - (x % i == 0), remain);
int mx = y + remain * i;
if (mx <= res_mn) res_mn = mx, res_d = i;
}
// cout << res_d << " " << res_mn << endl;
for (int i = res_mn, t = 0; t < n; i -= res_d, t += 1) cout << i << " ";
puts("");
}
return 0;
}
D.Decrease the Sum of Digits
题意: 给定n和s,每次操作可以把n += 1,求至少操作多少次后能够使得n的每位数字之和小于等于s。
题解: 记n得每位之和为sum(n),如果sum(n) <= s,那么输出0;否则从最低为开始(为了保证操作次数尽可能小),如果当前sum(n)>s,那么把n得当前位数+1,直到进位(不进位的话sum(n)只增不减)。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
LL n, m, T, s;
int check(LL x) {
int res = 0;
while(x) {
res += x % 10;
x /= 10;
}
return res;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> T;
while(T--) {
cin >> n >> s;
if (check(n) <= s) {
cout << 0 << endl;
continue;
}
LL add = 0, res = 0, bit = 1;
for (int i = 0; i < 18; ++i) {
int cur = n / bit % 10;
add = (10 - cur) * bit;
bit *= 10;
res += add;
n += add;
if (check(n) <= s) break;
}
cout << res << endl;
}
return 0;
}
E. Two Platforms
题意: 给定一张竖直平面上n个点,每个点坐标位(xi, yi),给定2个板子,板子的长度均为k。问将两个板子放置在哪可以保证两个板子接到的点数和最多。
∑
n
<
=
2
∗
1
0
5
,
x
i
<
=
1
0
9
,
y
i
<
=
1
0
9
,
1
<
=
k
<
=
1
0
9
\sum n <= 2*10^5, x_i<=10^9, y_i <= 10^9, 1 <= k <= 10^9
∑n<=2∗105,xi<=109,yi<=109,1<=k<=109
题解: 动态规划处理,r[i]表示用一块板子在i右侧能够接到的点最多为多少,l[i]表示用一块板子在i左侧能够接到的点最多为多少。那么答案就是
r
e
s
=
m
a
x
{
l
[
i
]
+
r
[
i
+
1
]
}
。
res = max\lbrace l[i] + r[i + 1] \rbrace 。
res=max{l[i]+r[i+1]}。本题点的坐标到达
1
0
9
10^9
109,本来应该离散化,但是可以特殊处理、利用尺取的思想就可以避免离散化,具体见代码。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const MAXN = 2e5 + 10;
int n, m, T;
int l[MAXN], r[MAXN], x[MAXN];
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> T;
while(T--) {
cin >> n >> m;
for (int i = 1; i <= n + 1; ++i) l[i] = r[i] = 0;
for (int i = 1; i <= n; ++i) cin >> x[i];
for (int i = 1, t; i <= n; ++i) cin >> t;
sort(x + 1, x + 1 + n);
for (int i = 1, j = 1; i <= n; ++i) {
while(j < i && x[i] - x[j] > m) j++;
l[i] = max(i - j + 1, l[i - 1]);
}
for (int i = n, j = n; i >= 1; --i) {
while(i < j && x[j] - x[i] > m) j--;
r[i] = max(j - i + 1, r[i + 1]);
}
int res = 0;
for (int i = 1; i <= n; ++i) res = max(res, l[i] + r[i + 1]);
cout << res << endl;
}
return 0;
}
F. Subsequences of Length Two
题意: 给出两个字符串s和t,其中t的长度为2。现在可以将s中的字符最多修改k次,问修改后s中有多少子序列与t相同
题解: d p [ i ] [ j ] [ l ] dp[i][j][l] dp[i][j][l]代表前i个字符中修改j个字符,且出现 t [ 0 ] l t[0]l t[0]l次时的答案
然后根据 a [ i ] a[i] a[i]的情况进行更新即可,具体看代码
需要注意的是,如果t0=t1,只需要用公式求出
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int n, k;
LL dp[205][205][205];
string a, b;
int main() {
cin >> n >> k;
cin >> a >> b;
a = " " + a;
b = " " + b;
if (b[1] == b[2]) {
int s = 0;
for (int i = 1; i <= n; i++) {
if (a[i] == b[1]) s++;
}
s = min(n, s + k);
cout << s * (s - 1) / 2 << endl;
return 0;
}
memset(dp, 0x8c, sizeof dp);
LL res = 0;
for (int i = 0; i <= k; i++) dp[0][i][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= k; j++) {
for (int l = 0; l <= i; l++) {
dp[i][j][l] = dp[i - 1][j][l];
if (a[i] == b[1]) {
dp[i][j][l] = max(dp[i][j][l], dp[i - 1][j][l - 1]);
} else if (j) {
dp[i][j][l] = max(dp[i][j][l], dp[i - 1][j - 1][l - 1]);
}
if (a[i] == b[2]) {
dp[i][j][l] = max(dp[i][j][l], dp[i - 1][j][l] + l);
} else if (j) {
dp[i][j][l] = max(dp[i][j][l], dp[i - 1][j - 1][l] + l);
}
res = max(res, dp[i][j][l]);
}
}
}
cout << res << endl;
return 0;
}