Codeforces Round #667 (Div. 3)

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<=2105,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值