Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)

value0發表於2024-03-10

Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)

A - Spoiler

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 1010;

void solve()
{
    int l = -1;
    int r = -1;
    string s;
    cin >> s;
    for (int i = 0; i < s.size(); i++)
    {
        if (s[i] == '|')
        {
            if (l == -1)
            {
                l = i;
            }
            else
            {
                r = i;
            }
        }
    }
    cout << s.substr(0, l) + s.substr(r + 1) << endl;
}

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

B - Delimiter

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 1010;

void solve()
{
    vector<int> a;
    int x;
    while (cin >> x)
    {
        a.push_back(x);
    }
    for (int i = (int)a.size() - 1; i >= 0; i--)
    {
        cout << a[i] << endl;
    }
}

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

C - A+B+C

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 1010;

void solve()
{
    int n, m, l;
    cin >> n;
    vector<ll> a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    cin >> m;
    vector<ll> b(m + 1);
    for (int i = 1; i <= m; i++)
    {
        cin >> b[i];
    }
    cin >> l;
    vector<ll> c(l + 1);
    for (int i = 1; i <= l; i++)
    {
        cin >> c[i];
    }
    set<ll> s;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            for (int k = 1; k <= l; k++)
            {
                s.insert(a[i] + b[j] + c[k]);
            }
        }
    }
    int q;
    cin >> q;
    while (q--)
    {
        ll x;
        cin >> x;
        if (s.find(x) != s.end())
        {
            puts("Yes");
        }
        else
        {
            puts("No");
        }
    }
}

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

D - String Bags

解題思路:

\(dp[i][j]:考慮前i個字元揹包進行選擇,次數匹配到字串T前j個字元的最小選擇數\)

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 30;
const int N = 110;
ll dp[N][N];
void solve()
{
    string t;
    cin >> t;
    t = ' ' + t;
    int n;
    cin >> n;
    vector<vector<string>> g(n + 1, vector<string>());
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        for (int j = 1; j <= x; j++)
        {
            string s;
            cin >> s;
            g[i].push_back(s);
        }
    }
    for (int i = 0; i <= n + 1; i++)
    {
        for (int j = 1; j < t.size(); j++)
        {
            dp[i][j] = inf;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j < g[i].size(); j++)
        {
            int len = g[i][j].size();
            for (int k = 1; k <= (int)t.size() - 1; k++)
            {
                dp[i][k] = min(dp[i][k], dp[i - 1][k]);
                if (k < len)
                {
                    continue;
                }
                if (t.substr(k - len + 1, len) != g[i][j])
                {
                    continue;
                }
                dp[i][k] = min(dp[i][k], dp[i - 1][k - len] + 1);
            }
        }
    }
    if (dp[n][t.size() - 1] >= inf)
    {
        puts("-1");
    }
    else
    {
        cout << dp[n][t.size() - 1] << endl;
    }
}

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

E - Insert or Erase

解題思路:

由於元素值互不相同,記錄每個值的位置,連結串列操作。

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 30;
const int N = 5e5 + 10;
int a[N];
int l[N];
int r[N];
int idx;

void solve()
{
    int n;
    cin >> n;
    map<int, int> pos;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        l[i] = i - 1;
        r[i] = i + 1;
        pos[a[i]] = ++idx;
    }
    r[0] = 1;
    r[idx] = -1;
    int q;
    cin >> q;
    while (q--)
    {
        int t;
        cin >> t;
        if (t == 1)
        {
            int x, y;
            cin >> x >> y;
            int i = pos[x];
            pos[y] = ++idx;
            a[idx] = y;
            l[idx] = i;
            r[idx] = r[i];
            l[r[i]] = idx;
            r[i] = idx;
        }
        else
        {
            int x;
            cin >> x;
            int i = pos[x];
            l[r[i]] = l[i];
            r[l[i]] = r[i];
        }
    }
    int cur = 0;
    while (r[cur] != -1)
    {
        cout << a[r[cur]] << ' ';
        cur = r[cur];
    }
}

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

F - Earn to Advance

解題思路:

\(dist[x][y][i][j]:點(x,y)到(i,j)的最小花費\)

\(dp[i][j]:從(1,1)到(i,j)的最小步數,和最小步數時所剩的最大剩餘金幣數\)

暴力列舉從\((x,y)\)轉移到\((i,j)\),四維\(dp\)

程式碼:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 81;
ll a[N][N];
ll r[N][N];
ll d[N][N];
ll dist[N][N][N][N];
pii dp[N][N];

void solve()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cin >> a[i][j];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j < n; j++)
        {
            cin >> r[i][j];
        }
    }
    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cin >> d[i][j];
        }
    }
    memset(dist, 0x3f, sizeof dist);
    // dist求任意兩點間最短路
    for (int x = 1; x <= n; x++)
    {
        for (int y = 1; y <= n; y++)
        {
            dist[x][y][x][y] = 0;
            for (int i = x; i <= n; i++)
            {
                for (int j = y; j <= n; j++)
                {
                    if (i == x && j == y)
                    {
                        continue;
                    }
                    dist[x][y][i][j] = min(dist[x][y][i - 1][j] + d[i - 1][j], dist[x][y][i][j - 1] + r[i][j - 1]);
                }
            }
        }
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            // {步數,-(到達[i][j]時剩餘的錢)}
            // 取負數是為了方便按關鍵字比較大小
            dp[i][j] = {inf, 0};
        }
    }
    dp[1][1] = {0, 0};
    for (int x = 1; x <= n; x++)
    {
        for (int y = 1; y <= n; y++)
        {
            for (int i = x; i <= n; i++)
            {
                for (int j = y; j <= n; j++)
                {
                    if (i == x && j == y)
                    {
                        continue;
                    }
                    ll prew = -dp[x][y].se;
                    ll pret = dp[x][y].fi;
                    // 兩點間最短花費 - 之前(x,y)存下的錢 在(x,y)要存多久能存到一次走到(i, j)
                    ll t = (dist[x][y][i][j] - prew + a[x][y] - 1) / a[x][y];
                    // 如果t < 0說明之前剩了很多錢,足夠一步走來,不用存錢
                    if (t < 0)
                    {
                        t = 0;
                    }
                    // 現存金額為:(x,y)有的金額 + (x,y)時存的金額 - 路費
                    ll w = prew + t * a[x][y] - dist[x][y][i][j];
                    t += i + j - x - y;
                    dp[i][j] = min(dp[i][j], {t + pret, -w});
                }
            }
        }
    }

    cout << dp[n][n].fi << endl;
}

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

相似解法可做題:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
typedef double db;
#define fi first
#define se second
using i128 = __int128_t;
using piii = pair<ll, pair<ll, ll>>;
const ll inf = 1ll << 60;
const int N = 810;

void solve()
{
    int n, m, s;
    cin >> n >> m >> s;
    vector<ll> w(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i];
    }
    vector<vector<ll>> dist(n + 1, vector<ll>(n + 1, inf));
    vector<pii> dp(n + 1, {inf, 0});
    for (int i = 1; i <= n; i++)
    {
        dist[i][i] = 0;
    }
    for (int i = 1; i <= m; i++)
    {
        ll a, b, c;
        cin >> a >> b >> c;
        dist[a][b] = min(dist[a][b], c);
    }
    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
            }
        }
    }
    vector<int> p(n + 1);
    for (int i = 1; i <= n; i++)
    {
        p[i] = i;
    }
    // 排序是必要的,一定是從賺錢少的地方向多的轉移
    // 因為賺錢多的地方一直賺錢,然後剩下的路一次性走完就是從該處出發的最優方案
    sort(p.begin() + 1, p.end(), [&](int i, int j)
         { return w[i] < w[j]; });
    // for (int i = 1; i <= n; i++)
    // {
    //     cout << p[i] << ' ';
    // }
    // cout << endl;
    dp[1] = {0, -s};
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (i == j || dist[p[i]][p[j]] >= 1e12)
            {
                continue;
            }
            ll prew = -dp[p[i]].se;
            ll pret = dp[p[i]].fi;
            ll t = (dist[p[i]][p[j]] - prew + w[p[i]] - 1) / w[p[i]];
            if (t < 0)
            {
                t = 0;
            }
            ll cw = prew + t * w[p[i]] - dist[p[i]][p[j]];
            dp[p[j]] = min(dp[p[j]], {t + pret, -cw});
            // cout << dist[i][j] << ' ' << prew << ' ' << w[i] << endl;
            // cout << i << ' ' << j << ' ' << t << ' ' << cw << ' ' << dp[j].fi << ' ' << dp[j].se << endl;
        }
    }
    if (dp[n].fi >= inf)
    {
        cout << -1 << endl;
    }
    else
    {
        cout << dp[n].fi << endl;
    }
}

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

相關文章