牛客小白月赛86

牛客小白月赛86

A 水盐平衡

解题思路:

通分,然后比较分子大小。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;

ll gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

ll lcm(int a, int b)
{
    return a * b / gcd(a, b);
}

void solve()
{
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    ll t = lcm(b, d);
    ll k1 = t / b;
    ll k2 = t / d;
    a *= k1;
    c *= k2;
    if (a < c)
    {
        puts("Y");
    }
    else
    {
        puts("S");
    }
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

B 水平考试

解题思路:

模拟判断即可。

没有得5分的情况。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;

void solve()
{
    string a, b;
    cin >> a >> b;
    if (b.size() == 1)
    {
        if (a.size() > 1)
        {
            puts("0");
            return;
        }
        else
        {
            if (a != b)
            {
                puts("0");
                return;
            }
            else
            {
                puts("10");
                return;
            }
        }
    }
    else
    {
        vector<int> cnt(200);
        for (auto c : b)
        {
            cnt[c]++;
        }
        for (auto c : a)
        {
            if (cnt[c] == 0)
            {
                puts("0");
                return;
            }
            cnt[c]++;
        }
        puts("10");
    }
}

int main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C 数组段数

解题思路:

预处理前缀和。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;

void solve()
{
    int n, m;
    cin >> n >> m;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    vector<int> pre(n + 1);
    for (int i = 1; i <= n; i++)
    {
        if (a[i] == a[i - 1])
        {
            pre[i] = pre[i - 1];
        }
        else
        {
            pre[i] = pre[i - 1] + 1;
        }
    }
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        int ans = pre[r] - pre[l - 1];
        if (a[l - 1] == a[l])
        {
            ans++;
        }
        cout << ans << endl;
    }
}

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

D 剪纸游戏

解题思路:

搜索连通块,判断该连通块是否是矩形。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;

int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

void solve()
{
    int n, m;
    cin >> n >> m;
    vector<string> g(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> g[i];
        g[i] = ' ' + g[i];
    }
    vector<vector<bool>> vis(n + 1, vector<bool>(m + 1, false));
    auto check = [&](int a, int b)
    {
        if (a < 1 || a > n || b < 1 || b > m)
        {
            return false;
        }
        if (vis[a][b])
        {
            return false;
        }
        if (g[a][b] == '*')
        {
            return false;
        }
        return true;
    };
    ll ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (g[i][j] == '.' && !vis[i][j])
            {
                vector<pii> v(4, {i, j});
                int cnt = 0;
                auto bfs = [&](int x, int y)
                {
                    queue<pii> q;
                    q.push({x, y});
                    vis[x][y] = true;
                    while (q.size())
                    {
                        auto u = q.front();
                        q.pop();
                        int a = u.fi;
                        int b = u.se;
                        cnt++;
                        for (int i = 0; i < 4; i++)
                        {
                            int nx = a + dx[i];
                            int ny = b + dy[i];
                            if (check(nx, ny))
                            {
                                vis[nx][ny] = true;
                                if (nx <= v[0].fi && ny <= v[0].se)
                                {
                                    v[0] = {nx, ny};
                                }
                                if (nx <= v[1].fi && ny >= v[1].se)
                                {
                                    v[1] = {nx, ny};
                                }
                                if (nx >= v[2].fi && ny >= v[2].se)
                                {
                                    v[2] = {nx, ny};
                                }
                                if (nx >= v[3].fi && ny <= v[3].se)
                                {
                                    v[3] = {nx, ny};
                                }
                                q.push({nx, ny});
                            }
                        }
                    }
                };
                bfs(i, j);
                if (v[0].se == v[3].se && v[0].fi == v[1].fi && v[1].se == v[2].se && v[2].fi == v[3].fi)
                {
                    if ((v[1].se - v[0].se + 1) * (v[2].fi - v[1].fi + 1) == cnt)
                    {
                        ans++;
                    }
                }
                // for (auto t : v)
                // {
                //     cout << t.fi << ' ' << t.se << endl;
                // }
                // cout << i << ' ' << j << ' ' << ans << ' ' << cnt << endl;
            }
        }
    }
    cout << ans << endl;
}

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

E 可口蛋糕

解题思路:

对于每一个起点,答案是固定的。

我们先得到对于每个起点基本满足饱和度的边界,然后看从边界到最后所有满足饱和度的时候可口值的前缀和最大值。

由于本题数据范围为\(10^6\),只能用\(O(n)\)找最大。

\(ps:尝试用st表查区间最大值卡的死死的。\)

所以这里我们可以根据饱和值边界,记录连续段的起点。

然后从右往左用单调栈记录当前区间最大值,顺便根据饱和右边界,枚举左起点。

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;

void solve()
{
    int n, W;
    cin >> n >> W;
    vector<ll> w(n + 10), d(n + 10), prew(n + 10), pred(n + 10);
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i];
        prew[i] = prew[i - 1] + w[i];
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> d[i];
        pred[i] = pred[i - 1] + d[i];
    }
    vector<int> r(n + 1, -1);
    int idx = 1;
    ll ans = -1e18;
    vector<vector<int>> v(n + 10);
    for (int i = 1; i <= n; i++)
    {
        while (idx <= n && prew[idx] - prew[i - 1] < W)
        {
            idx++;
        }
        if (idx <= n)
        {
            r[i] = idx;
            v[idx].push_back(i);
            ans = max(ans, pred[r[i]] - pred[i - 1]);
        }
    }
    ll cur = 0;
    vector<ll> q;
    for (int i = n; i > 0; i--)
    {
        while (q.size() && pred[i] > q.back())
        {
            q.pop_back();
        }
        q.push_back(pred[i]);
        for (auto j : v[i])
        {
            ans = max(ans, q.front() - pred[j - 1]);
        }
    }
    cout << ans << endl;
}

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

F 喜欢序列

解题思路:

首先,不难发现,如果一段序列可以连在一起,全部连在一个整体的贡献一定大于将他分开的贡献。

我们构建差分序列。

对于差分序列中连续的\(1\)看作一个整体线段。

我们要做的就是在修改过程中不断合并线段(或者说区间)。

由于本题中的连接性质差分数组中可以完美体现,所以我们接下来只看差分数组即可。

差分数组上进行区间修改在这不多赘述\((b[l] + w,b[r + 1] - w)\)

在修改过程中,如果原本不为\(1\)的位置变为了\(1\)我们就要进行合并,并更新合并带来的总体贡献。

在修改过程中,如果原本为\(1\)的位置变为了其他数字我们就要进行分裂,并更新合并带来的总体贡献。

举例:

合并:\((....)(x...)\to(....x...)\)

分类:\((....x...) \to (....)(x...)\)

代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;

void solve()
{
    int n, m;
    cin >> n >> m;
    vector<ll> a(n + 1), b(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        b[i] = a[i] - a[i - 1];
    }
    ll ans = 0;
    set<pii> s;
    int l = 1;
    auto add = [&](int l, int r)
    {
        ll len = r - l + 1;
        s.insert({l, r});
        ans += len * len;
    };
    auto del = [&](int l, int r)
    {
        ll len = r - l + 1;
        s.erase({l, r});
        ans -= len * len;
    };
    for (int i = 2; i <= n; i++)
    {
        if (b[i] != 1)
        {
            add(l, i - 1);
            l = i;
        }
    }
    add(l, n);
    auto deal = [&](int idx, ll w)
    {
        if (idx == 1 || idx > n)
        {
            return;
        }
        ll t = b[idx];
        b[idx] += w;
        if (b[idx] == 1)
        {
            //(....)(x...)
            //(....x...)
            auto it = s.lower_bound({idx, -1});
            auto cur = *it;
            auto p = *prev(it);
            del(p.fi, p.se);
            del(cur.fi, cur.se);
            add(p.fi, cur.se);
        }
        else if (t == 1)
        {
            //(....x...)
            //(....)(x...)
            auto it = s.lower_bound({idx, -1});
            auto cur = *prev(it);
            del(cur.fi, cur.se);
            add(cur.fi, idx - 1);
            add(idx, cur.se);
        }
    };
    while (m--)
    {
        int l, r, w;
        cin >> l >> r >> w;
        if (w != 0)
        {
            deal(l, w);
            deal(r + 1, -w);
        }
        cout << ans << endl;
    }
}

int main()
{
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}
posted @ 2024-01-19 21:11  value0  阅读(40)  评论(0)    收藏  举报