Educational Codeforces Round 161 (Rated for Div. 2)

Educational Codeforces Round 161 (Rated for Div. 2)

A - Tricky Template

代码:

#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;
    cin >> n;
    string a, b, c;
    cin >> a >> b >> c;
    for (int i = 0; i < n; i++)
    {
        if (a[i] == b[i] && c[i] != a[i])
        {
            puts("YES");
            return;
        }
        else if (a[i] != b[i] && c[i] != a[i] && c[i] != b[i])
        {
            puts("YES");
            return;
        }
    }
    puts("NO");
}

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

B - Forming Triangles

解题思路:

要么三根一样长,要么两根一样长。

代码:

#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;
    cin >> n;
    vector<ll> a(n + 1);
    map<ll, ll> cnt;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        cnt[a[i]]++;
    }
    ll ans = 0;
    ll cur = 0;
    for (int i = 0; i <= n; i++)
    {
        ans += (cnt[i] * (cnt[i] - 1) * (cnt[i] - 2)) / 6;
        ans += (cnt[i] * (cnt[i] - 1)) / 2 * cur;
        cur += cnt[i];
    }
    cout << ans << endl;
}

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

C - Closest Cities

解题思路:

求花费前缀和、后缀和,分别代表两个方向。

如果是最近就花费一,否则花费距离差。

代码:

#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;
    cin >> n;
    vector<ll> a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    vector<ll> pre(n + 1), suf(n + 1);
    pre[1] = 0;
    suf[n] = a[n];
    for (int i = 2; i <= n; i++)
    {
        if (i == 2)
        {
            pre[i] = pre[i - 1] + 1;
        }
        else if (i == n)
        {
            if (a[n - 1] - a[n - 2] > a[n] - a[n - 1])
            {
                pre[i] = pre[i - 1] + 1;
            }
            else
            {
                pre[i] = pre[i - 1] + a[n] - a[n - 1];
            }
        }
        else
        {
            if (a[i - 1] - a[i - 2] > a[i] - a[i - 1])
            {
                // cout << i << endl;
                pre[i] = pre[i - 1] + 1;
            }
            else
            {
                pre[i] = pre[i - 1] + a[i] - a[i - 1];
            }
        }
    }
    for (int i = n - 1; i; i--)
    {
        if (i == n - 1)
        {
            suf[i] = suf[i + 1] + 1;
        }
        else if (i == 1)
        {
            if (a[3] - a[2] > a[2] - a[1])
            {
                suf[i] = suf[i + 1] + 1;
            }
            else
            {
                suf[i] = suf[i + 1] + a[2] - a[1];
            }
        }
        else
        {
            if (abs(a[i + 1] - a[i + 2]) > abs(a[i] - a[i + 1]))
            {
                suf[i] = suf[i + 1] + 1;
            }
            else
            {
                suf[i] = suf[i + 1] + a[i + 1] - a[i];
            }
        }
    }
    // cout << pre[4] << endl;
    int m;
    cin >> m;
    while (m--)
    {
        int x, y;
        cin >> x >> y;
        if (x < y)
        {
            cout << pre[y] - pre[x] << endl;
        }
        else
        {
            cout << suf[y] - suf[x] << endl;
        }
    }
}

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

E - Increasing Subsequences

解题思路:

一个长度为n单调递增的序列,他的严格单调递增子序列数量为2n

询问要求子序列数为len。我们确定上下界2alen2a+1

我们考虑先构造基序列(1,2,3,...,a),在其基础上添砖加瓦。

观察一下,不难发现,不同位置加入最小数,递增子序列的数量会增加不同的2的整数次幂个。

举例:

(1,2,3,4,5)32

(1,2,3,4,5,1)32+1

(1,2,3,4,1,5)32+2

(1,2,3,1,4,5)32+4

(1,2,1,3,4,5)32+8

由于2alen2a+1,所以我们将剩下的需求二进制拆分,序列长度一定不会增加超过log(n)

代码:

#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()
{
    ll n;
    cin >> n;
    ll l = 0;
    ll cur = 0;
    while ((1ll << cur) <= n)
    {
        l = 1ll << cur;
        cur++;
    }
    cur--;
    list<int> q;
    for (int i = 1; i <= cur; i++)
    {
        q.push_back(i);
    }
    ll res = n - l;
    auto find = [&](int x)
    {
        for (auto it = q.begin(); it != q.end(); it++)
        {
            if (*it == x)
            {
                return it;
            }
        }
        return q.end();
    };
    map<ll, int> mp;
    for (int i = 0; i <= cur; i++)
    {
        mp[i] = cur - i + 1;
    }
    for (int i = 0; i <= cur; i++)
    {
        if (res >> i & 1)
        {
            auto it = find(mp[i]);
            q.insert(it, 1);
        }
        // for (auto it : q)
        // {
        //     cout << it << ' ';
        // }
        // cout << endl;
    }
    cout << q.size() << endl;
    for (auto it : q)
    {
        cout << it << ' ';
    }
    cout << endl;
}

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

D - Berserk Monsters

解题思路:

对于第一次,我们要看所有的怪物情况。

对于之后的判断,我们只看那些左右两边有怪物更新的怪物。因为左右不变,之前存在之后一样会存在。

如果这样看的话,每次消灭已知怪物,我们就要记录他身边的两只怪物作为下一轮要看的怪物。

那么最多总共最多判断2n次。

我们用链表模拟,set记录即可。

时间复杂度O(nlogn)

代码:

#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()
{
    ll n;
    cin >> n;
    vector<ll> a(n + 10), b(n + 10), l(n + 10), r(n + 10);
    vector<bool> die(n + 10, false);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
        l[i] = i - 1;
        r[i] = i + 1;
    }
    // 记录需要判断是否会被击败的怪物的下标
    set<int> s;
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        // 这里判断不受链表删除影响
        if (a[i - 1] + a[i + 1] > b[i])
        {
            s.insert(l[i]);
            s.insert(r[i]);
            die[i] = true;
            l[r[i]] = l[i];
            r[l[i]] = r[i];
            cnt++;
            // cout << i << endl;
        }
    }
    cout << cnt << ' ';
    for (int i = 2; i <= n; i++)
    {
        cnt = 0;
        // 记录被击败的怪物的下标,进行延迟更新
        set<int> t;
        for (auto idx : s)
        {
            if (die[idx] || idx == 0 || idx == n + 1)
            {
                continue;
            }
            // 这里先不进行链表删除,因为会影响判断
            if (a[l[idx]] + a[r[idx]] > b[idx])
            {
                // cout << i << ' ' << idx << endl;
                cnt++;
                t.insert(idx);
            }
        }
        // 记录下一轮需要判断是否会被击败的怪物的下标
        s.clear();
        // 判断完后,再进行链表删除操作,延迟更新
        for (auto idx : t)
        {
            die[idx] = true;
            s.insert(r[idx]);
            s.insert(l[idx]);
            l[r[idx]] = l[idx];
            r[l[idx]] = r[idx];
        }
        cout << cnt << ' ';
    }
    cout << endl;
}

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

F - Replace on Segment

解题思路:

区间操作加O(n4)似乎可过的复杂度,考虑区间dp

我们对于将一个区间变成含有相同的数x有两种操作方向。

  1. 保留x不动,将不含x的子区间一一变为x
  2. 先使得整个区间都不包含x,然后一步到位。

f[i][j][x]:ijx

g[i][j][x]:ijx

对于f的求取如上模拟:

f[l][r][x]=min(f[l][r][x],g[l][r][x]+1)

对于g我们发现,处理简单地将区间合并,我们使得区间所有的数都变成一个非x的数同样符合定义。

所以,我们最后可以通过fg进行更新。

g[l][r][x]=min(g[l][r][x],f[l][r][invx])

代码:

#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;
const int N = 110;
// f[i][j][x]:将从i到j的区间中的数全部变成x的最小操作次数
int f[N][N][N];
// g[i][j][x]:将从i到j的区间中的x全部去除的最小操作次数
int g[N][N][N];
void solve()
{
    int n, x;
    cin >> n >> x;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = i; j <= n; j++)
        {
            for (int k = 1; k <= x; k++)
            {
                f[i][j][k] = 1e9 + 10;
                g[i][j][k] = 1e9 + 10;
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= x; j++)
        {
            if (a[i] == j)
            {
                f[i][i][j] = 0;
                g[i][i][j] = 1;
            }
            else
            {
                f[i][i][j] = 1;
                g[i][i][j] = 0;
            }
        }
    }
    for (int i = n - 1; i; i--)
    {
        for (int j = i + 1; j <= n; j++)
        {
            for (int k = i; k < j; k++)
            {
                for (int val = 1; val <= x; val++)
                {
                    // cout << i << ' ' << k << ' ' << k + 1 << ' ' << j << endl;
                    f[i][j][val] = min(f[i][j][val], f[i][k][val] + f[k + 1][j][val]);
                    g[i][j][val] = min(g[i][j][val], g[i][k][val] + g[k + 1][j][val]);
                    f[i][j][val] = min(f[i][j][val], g[i][j][val] + 1);
                }
            }
            for (int val = 1; val <= x; val++)
            {
                for (int inv = 1; inv <= x; inv++)
                {
                    if (val == inv)
                    {
                        continue;
                    }
                    g[i][j][val] = min(g[i][j][val], f[i][j][inv]);
                }
            }
        }
    }
    // cout << f[1][8][3] << endl;
    // cout << g[1][8][2] << endl;
    int ans = 1e9 + 10;
    for (int i = 1; i <= x; i++)
    {
        ans = min(ans, f[1][n][i]);
    }
    cout << ans << endl;
}

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

    return 0;
}
posted @   value0  阅读(109)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示