Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final)

CF681B

题目链接

题目大意

现在有n个建筑平行排列,用一个长度为n的01字符串代表这个n个建筑,如果字符串某个位置为1,代表这个建筑下面地雷,为0则代表没有,现在设定一种规则,我们可以花 \(a\) 个硬币引爆一个地雷,这个地雷的位置为 \(x\) ,如果 \(x - 1\) 或者 \(x + 1\) 位置处存在地雷,那么这个地雷也将被引爆。我们也可以在没有地雷的建筑下埋地雷,这需要花费 \(b\) 个硬币,然后我们在尝试引爆,现在我们需要引爆所有的地雷来确保城市的安全,问最少需要多少硬币就可以引爆所有地雷。

题解

本题的想法比较直接,考虑两个1的连续区间 \([l_1, r_1]\)\([l_2, r_2]\),如果在这两个区间中间的那个区间填1的代价小于分别引爆这两个区间,那么就采取前者的方案,否则,采取后面的那个方案,具体到实现中就是 \(2 * a \leq a + b * d\),也就是 \(a \leq b * d\) 的时候,我们采取前者方案,否则后者。那我们遍历这个字符串,由于我们不管是填补引爆还是分别引爆,都会将所有的地雷引爆掉,所以这个也就相当于这个字符串 \([l_1, r_2]\) 都是1,所以考虑两个相邻连续1序列必然是最优的,所以我们继续考虑下一个1的连续区间 \([l_3, r_3]\) 也是如此,因此,我们遍历整个字符串即可。

AC代码
#include <bits/stdc++.h>

using namespace std;
#define DBG(x)                         \
    (void)(cout << "L" << __LINE__     \
                << ": " << #x << " = " \
                << (x) << '\n')
#define Lower_bound(v, x) distance(v.begin(), lower_bound(v.begin(), v.end(), x))
#define Upper_bound(v, x) distance(v.begin(), upper_bound(v.begin(), v.end(), x))
typedef long long ll;
const long double PI = (acos(-1));
const long double EPS = 0.0000000001;
const int INF = 0x3f3f3f3f;
const int maxn = 1100000;
void run_case()
{
    int T;
    cin >> T;
    while (T--)
    {
        int a, b;
        cin >> a >> b;
        string s;
        cin >> s;
        int ans = 0;
        int d = 1e6;
        for (int i = 0; i < s.size(); i++)
        {
            if (s[i] == '1')
            {
                ans += min(a, b * d);
                d = 0;
            }
            else d++;
        }
        cout << ans << "\n";
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << setiosflags(ios::fixed) << setprecision(12);
    run_case();
    cout.flush();
    return 0;
}

CF681C

题目链接

题目大意

Petya准备他的生日,准备订 $ n $ 盘菜,有两种方案,一种是让快递员给他送来,一种是自己去取,快递员给他送来,快递员送来是一个并行的过程,每个菜消耗 \(b_i\) 时间,自己取是一个连续的过程,每个菜消耗 \(a_i\) 时间,问最少需要多少时间。

题解

本题的切入点在于快递员送来是一个并行的过程,所以我们用一个结构体维护 \(a\)\(b\) 数组,对结构体按 $ a $ 数组元素从小到大进行排序,然后遍历 $ a $ 数组,此时遍历到的第 $ i $ 个元素就是前 $ i $ 盘菜所需要花的时间。同时,我们维护 $ b $ 数组的前缀和和 $ b $ 数组中元素总和,更新 $ ans $ 为 max{sum - pre, a[i].first}即可。

AC代码
#include <bits/stdc++.h>

using namespace std;
#define DBG(x)                         \
    (void)(cout << "L" << __LINE__     \
                << ": " << #x << " = " \
                << (x) << '\n')
#define Lower_bound(v, x) distance(v.begin(), lower_bound(v.begin(), v.end(), x))
#define Upper_bound(v, x) distance(v.begin(), upper_bound(v.begin(), v.end(), x))
typedef long long ll;
const long double PI = (acos(-1));
const long double EPS = 0.0000000001;
const int INF = 0x3f3f3f3f;
const int maxn = 1100000;
pair<int, int> a[maxn];
void run_case()
{
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i].first;
        }
        ll sum = 0;
        for (int i = 1; i <= n; i++) 
        {
            cin >> a[i].second;
            sum += 1ll * a[i].second;
        }
        sort(a + 1, a + 1 + n);
        ll ans = sum;
        ll pre = 0;
        for (int i = 1; i <= n; i++)
        {
            pre += 1ll * a[i].second;
            ans = min(ans, max(sum - pre, 1ll * a[i].first));
        }
        cout << ans << "\n";
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << setiosflags(ios::fixed) << setprecision(12);
    run_case();
    cout.flush();
    return 0;
}

CF681D

题目链接

题目大意

给你一个数组\(a\),每次操作可以将数组的前\(k\)个元素或者后\(k\)个元素减1,问经过有限次的操作能不能把这个数组全部变成0。

题解

前缀区间和后缀区间减\(1\),我们可以自然想到使用差分的方法来解决这个问题,设一个数组\(a\),它的差分数组为\(df\),对\(a\)数组中区间\([l,r]\)中所有的元素减\(1\),相当于对差分数组\(df[l]-1\)\(df[r+1]+1\),所以在这个问题中,我们只需要保证\(df[1] = 0\),然后\(df\)数组其余所有元素为0即可。在对前缀区间操作时,差分数组\(df[1]\)减小,数组中其余元素增加,进行后缀区间操作时,因为我们这时候是对\(d[n+1]\)进行加1,所以对这个问题没有影响,我们可以任意把差分数组中大于\(0\)的元素减到\(0\),因此,我们只需要判断\(d[1]\)是否大于等于差分数组中负数之和的绝对值即可。

#include <bits/stdc++.h>

using namespace std;
#define DBG(x)                         \
    (void)(cout << "L" << __LINE__     \
                << ": " << #x << " = " \
                << (x) << '\n')
#define Lower_bound(v, x) distance(v.begin(), lower_bound(v.begin(), v.end(), x))
#define Upper_bound(v, x) distance(v.begin(), upper_bound(v.begin(), v.end(), x))
typedef long long ll;
const long double PI = (acos(-1));
const long double EPS = 0.0000000001;
const int INF = 0x3f3f3f3f;
const int maxn = 110000;
int a[maxn];
int df[maxn];
void run_case()
{
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= n; i++)
        {
            df[i] = a[i] - a[i - 1];
        }
        int cnt = 0;
        for (int i = 1; i <= n; i++)
        {
            if (df[i] < 0) cnt += df[i];
        }
        cnt = -cnt;
        if (cnt > df[1]) cout << "NO\n";
        else cout << "YES\n";
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << setiosflags(ios::fixed) << setprecision(12);
    run_case();
    cout.flush();
    return 0;
}
posted @ 2020-11-12 09:51  zdy_1214  阅读(131)  评论(0)    收藏  举报