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;
}