Codeforces Round 933 (Div. 3)(A~E)

文章讨论了五种与Rudolf相关的问题,涉及数组操作、字符串查找、动态规划以及比赛策略。通过循环遍历、条件判断和优化技巧,解决了一系列关于整数、字符串和比赛状态更新的问题。
摘要由CSDN通过智能技术生成

A. Rudolf and the Ticket

思路:按照题意写两重循环模拟即可

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;

int n, m, k;
int a[N], b[N];
void solve()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= m; i++)
    {
        cin >> b[i];
    }
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (a[i] + b[j] <= k)
            {
                cnt++;
            }
        }
    }
    cout << cnt << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T;
    // T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

B. Rudolf and 121

思路:循环遍历2~n-1,判断是否可以通过操作使得全部数为0,当a[i-1]>a[i]*2时,说明a[i-1]一定不能变成0,否则的话将a[i-1]=0,这样做的代价是a[i]-=2*a[i-1],a[i+1]-=a[i-1],最后判断整个数组是不是为都是0。

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;

int n;
int a[N];
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    bool ok = true;
    for (int i = 2; i <= n - 1; i++)
    {
        if (a[i - 1] * 2 > a[i]) // 判断是否可以通过操作使得a[i-1]==0
        {
            ok = false;
            break;
        }
        else // 进行操作后的状态
        {
            a[i] -= 2 * a[i - 1];
            a[i + 1] -= a[i - 1];
            a[i - 1] = 0;
        }
    }
    if (a[n - 1] != 0 || a[n] != 0) // 在上面的循环中已经判断了(1~n-2)中的数是否为0
    {
        ok = false;
    }
    cout << (ok == true ? "YES" : "No") << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T;
    // T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

C. Rudolf and the Ugly String

思路:当在串s中发现“map”或“pie”时,跳过即可,此时cnt+=1

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;

string s;
int n;
void solve()
{
    cin >> n >> s;
    string t1 = "map", t2 = "pie";
    int cnt = 0;
    for (int i = 0; i < n; i++)
    {
        if (s.substr(i, 3) == t1 || s.substr(i, 3) == t2)
        {
            i += 2;
            cnt++;
        }
    }
    cout << cnt << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T;
    // T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

D. Rudolf and the Ball Game

比赛时一开始就想到了这个思路,但由于细节有点多,debug了一个小时多。

思路:首先我们用book[]数组表示当book[i]==true时,表示球可能在i位置,我们用t[]数组表示当进行一次操作后从book[]数组中有球的位置转移到操作后有球的位置,最后判断m个操作后book[]中哪个位置有球即可。这么说可能不太清晰,具体还是看代码注释吧。

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;

int n, m, x;
bool book[N], t[N];
void solve()
{
    cin >> n >> m >> x;
    for (int i = 1; i <= n; i++)
    {
        book[i] = t[i] = false; // 初始化
    }
    book[x] = true; // 一开始球在x位置
    while (m--)
    {
        char ch;
        int d;
        cin >> d >> ch;
        if (ch == '?')
        { // 可能顺可能逆
            for (int i = 1; i <= n; i++)
            {
                if (book[i])
                {
                    // 顺时针经过操作后可能有球的位置
                    if (i + d <= n)
                    {
                        t[i + d] = true;
                    }
                    else
                    {
                        t[i + d - n] = true;
                    }
                    // 逆时针经过操作后可能有球的位置
                    if (i - d > 0)
                    {
                        t[i - d] = true;
                    }
                    else
                    {
                        t[n - (d - i)] = true;
                    }
                }
            }
        }
        else if (ch == '0')
        { // 顺时针
            for (int i = 1; i <= n; i++)
            {
                if (book[i])
                {
                    if (i + d <= n)
                    {
                        t[i + d] = true;
                    }
                    else
                    {
                        t[i + d - n] = true;
                    }
                }
            }
        }
        else if (ch == '1')
        { // 逆时针
            for (int i = 1; i <= n; i++)
            {
                if (book[i])
                {
                    if (i - d > 0)
                    {
                        t[i - d] = true;
                    }
                    else
                    {
                        t[n - (d - i)] = true;
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++)
        {
            book[i] = t[i]; // 先将t[i]中的状态转移到book[i]中
            t[i] = false;   // 然后将t[i]设置为false,以便下一次操作进行转移
        }
    }
    int cnt = 0; // 统计答案
    for (int i = 1; i <= n; i++)
    {
        if (book[i])
        {
            cnt++;
        }
    }
    cout << cnt << '\n';
    for (int i = 1; i <= n; i++)
    {
        if (book[i])
        {
            cout << i << " ";
        }
    }
    cout << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T;
    // T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

E. Rudolf and k Bridges

比赛时没做出来,卡在怎么O(n)的在一行建桥后得到所花费的最小代价,想到用DP,但不会单调队列优化。有了这个之后就简单了,我们只需要有前缀和处理一下,然后从前向后遍历去最小即可。

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;

int n, m, k, d;
int sum[N], cost[N], dp[N];
void solve()
{
    cin >> n >> m >> k >> d;
    for (int i = 1; i <= n; i++)
    {
        sum[i] = cost[i] = 0;
    }
    int a[n + 1][m + 1];
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            dp[j] = 0;
        }
        deque<int> q;
        q.clear();
        dp[1] = a[i][1] + 1;
        q.push_back(1);

        for (int j = 2; j <= m; j++)
        {
            while (!q.empty() && j - q.front() > d + 1)
            {
                q.pop_front();
            }
            dp[j] = dp[q.front()] + a[i][j] + 1;
            while (!q.empty() && dp[q.back()] > dp[j])
            {
                q.pop_back();
            }
            q.push_back(j);
        }
        cost[i] = dp[m];
    }

    for (int i = 1; i <= n; i++)
    {
        sum[i] = sum[i - 1] + cost[i];
    }
    int res = 1e18;
    for (int i = k; i <= n; i++)
    {
        res = min(res, sum[i] - sum[i - k]);
    }
    cout << res << '\n';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T;
    // T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值