Loading

AtCoder Beginner Contest 344




B - Delimiter

难度: ⭐

题目大意

把一个数组倒序输出;

解题思路

没啥好说的;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 4e6 + 10, mod = 998244353, inf = 2e18;
typedef pair<int, int> PII;
int n, m, idx;
void dfs(){
    int a;
    cin >> a;
    if(a == 0){
        cout << a << endl;
        return;
    }
    dfs();
    cout << a << endl;
}
signed main(){
    dfs();
	return 0;
}




C - A+B+C

难度: ⭐⭐

题目大意

给定三个数组A, B, C以及一个目标数组X, 对于X中的每一个数, 询问是否可以从数组A, B, C中各取一个数相加得到;

解题思路

数组A, B, C的长度很小, 可以打暴力把所有可能的和求出来;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 4e6 + 10, mod = 998244353, inf = 2e18;
typedef pair<int, int> PII;
int n, m, l, q;
int A[N], B[N], C[N];
map<int, int> mp;
signed main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> A[i];
    cin >> m;
    for(int i = 1; i <= m; i++) cin >> B[i];
    cin >> l;
    for(int i = 1; i <= l; i++) cin >> C[i];
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            for(int k = 1; k <= l; k++){
                int a = A[i] + B[j] + C[k];
                mp[a]++;
            }
        }
    }
    cin >> q;
    for(int i = 1; i <= q; i++){
        int a;
        cin >> a;
        if(mp[a]) cout << "Yes" << endl;
        else cout << "No" << endl;
    } 
	return 0;
}




D - String Bags

难度: ⭐⭐⭐

题目大意

现在有n个盒子, 一个字符串S, 一个空字符串T, 每个盒子里有若干个字符串, 我们从第一个盒子开始依次遍历, 对于每个盒子我们可以花费一元取出其中的一个字符串接在T后面, 当然也可以不取, 也就是跳过该盒子; 问我们最少花费多少元可以让T变成字符串S; 注意每个盒子只能最多取一个, 而且盒子要按顺序遍历;

解题思路

很明显的dp; 状态表示dp[i][j]表示用前i个盒子拼出字符串S的前j个字母所需要的最少花费; 对于某个盒子中的某个字符串str, 我们可以先遍历S去找是否有str, 设str在S中的位置是pos, 那么我们就可以用dp[i - 1][pos - 1] + 1来进行状态转移;
写代码时我们可以把第一维优化掉, 但是要注意如果S中有多个str, 那么我们只用一维数组时会相当于用dp[i][pos - 1] + 1来进行状态转移, 所以我们要提前备份一下, 再所有情况都更新完之后再更新;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e5 + 10, mod = 998244353, inf = 2e18;
typedef pair<int, int> PII;
int n, m, l, q;
int dp[110];
signed main(){
    string s;
    cin >> s >> n;
    s = ' ' + s; 
    for(int j = 0; j < s.size(); j++) dp[j] = inf;
    dp[0] = 0;
    for(int i = 1; i <= n; i++){
        int x;
        cin >> x;
        int dp2[110];
        memcpy(dp2, dp, sizeof dp2);
        for(int j = 1; j <= x; j++){
            string str;
            cin >> str;
            for(int k = 1; k < s.size(); k++){
                if(s[k] == str[0] && k + str.size() - 1 < s.size()){
                    bool f = true;
                    for(int h = 0; h < str.size(); h++){
                        if(s[k + h] != str[h]){
                            f = false;
                            break;
                        }
                    }
                    if(f) dp2[k + str.size() - 1] = min(dp2[k + str.size() - 1], dp[k - 1] + 1);
                }
            }
        }
        for(int k = 0; k < s.size(); k++) dp[k] = dp2[k];
    }
    if(dp[s.size() - 1] <= n) cout << dp[s.size() - 1];
    else cout << -1;
	return 0;
}




E - Insert or Erase

难度: ⭐⭐⭐

题目大意

给定一个长度为n的数组, 数组中每个数都不一样; 现在进行m次操作, 操作分两种: 一是可以把数字y插入到数字x后面, 二是删除数字x; 操作保证数组一定存在数字x;

解题思路

多次插入操作可以想到用链表来操作, 但是问题在于如果快速定位数字x的位置, 因为每次修改后都会引起后面所有数字的位置变化, 维护下标的代价太大; 所以不能从下标入手, 既然每个数都不同, 那么不如直接一点, 抛弃下标的概念, 完全用链表来操作; mp[x].l表示数字x的前一个数是多少, mp[x].r表示数字y的后一个数是多少; 相应的我们需要标记数组的起点和终点, x的数据范围是1 ~ 1e9, 那么我们只要把链表的起点和终点都设为数字0即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 2e18;
typedef pair<int, int> PII;
int n, m;
struct node{
    int l, r;
};
map<int, node> mp;
signed main(){
    cin >> n;
    int x = 0;
    for(int i = 1; i <= n; i++){
        int a;
        cin >> a;
        mp[x].r = a;
        mp[a].l = x;
        mp[a].r = 0;
        x = a;
    }
    cin >> m;
    while(m--){
        int a, b, c;
        cin >> a;
        if(a == 1){
            cin >> b >> c;
            mp[c].l = b;
            mp[c].r = mp[b].r;
            mp[mp[b].r].l = c;
            mp[b].r = c;
        }
        else {
            cin >> b;
            mp[mp[b].l].r = mp[b].r;
            mp[mp[b].r].l = mp[b].l;
        }
    }
    x = 0;
    while(1){
        cout << mp[x].r << ' ';
        x = mp[x].r;
        if(mp[x].r == 0) break;
    }
	return 0;
}




F - Earn to Advance

难度: ⭐⭐⭐⭐

题目大意

现有一个n * n的网格, 小莫初始在(1, 1), 他的目的是到达(n, n)点; 并且小莫每次只能往下或者往右走; 并且在相邻的两个网格之间移动是有代价的; 每个格子也有格子的钱数; 如果小莫在这个格子上停留一次就可以得到这个钱数, 可以取无限次; 小莫初始钱数为0; 问小莫走到(n, n)的最短步数是多少;

解题思路

最短路问题; 我们可以记录一下当前路径上的哪个格子的钱数最多, 以后缺钱就可以选择在这个格子停留赚钱; 但是这样最短路的状态有三个变量(num(步数), maxn(最大值), now(当前钱数)) 这样最优情况就变得难以判断, 因为我们肯定是优先步数最少的, 但是接下来我们无法判断选择最大值较大的还是当前钱数较多的; 对此我们可以把最大值拿出来, 把dis数组变成一个二维数组, dis[a][b]表示到底点a并且以b点为最大值的状态; 最后遍历最大值找到最小步数即可;
在最短路中, 我们首先要看当前钱数是否可以通过, 因为这涉及我们到底需要花多少步才能走到下个格子, 才能和最初情况进行比较, 然后就是普通的双重情况最短路问题;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, 1, -1};
int n, m, k;
struct node{
    int u, d;
};
struct node1{
    int u, maxn, num, now;
    bool operator<(const node1 a) const{
        if(num == a.num) return maxn < a.maxn;
        return num > a.num;
    }
};
int P[N];
node dis[81 * 81][81 * 81];
vector<node> v[N];
bool st[81 * 81][81 * 81];
int solve(){
    priority_queue<node1> q;
    q.push({1, 1, 1, P[1]});
    dis[1][1] = {P[1], 1};
    while(q.size()){
        auto t = q.top();
        q.pop();
        int u = t.u, maxn = t.maxn, num = t.num, now = t.now;
        if(st[u][maxn]) continue;
        st[u][maxn] = true;
        for(auto adj : v[u]){
            int x = adj.u, d = adj.d;
            int a = maxn;
            if(P[x] > P[maxn]) a = x; 
            if(dis[u][maxn].u >= d){
                if(dis[x][a].d > dis[u][maxn].d + 1){
                    dis[x][a].d = dis[u][maxn].d + 1;
                    dis[x][a].u = dis[u][maxn].u - d;
                    q.push({x, a, dis[x][a].d, dis[x][a].u});
                }
                else if(dis[x][a].d == dis[u][maxn].d + 1 && dis[x][a].u < dis[u][maxn].u - d){
                    dis[x][a].d = dis[u][maxn].d + 1;
                    dis[x][a].u = dis[u][maxn].u - d;
                    q.push({x, a, dis[x][a].d, dis[x][a].u});
                }
            }
            else{
                int b = (d - dis[u][maxn].u) / P[maxn] + ((d - dis[u][maxn].u) % P[maxn] != 0);
                int c = b * P[maxn] + dis[u][maxn].u;
                if(dis[x][a].d > dis[u][maxn].d + 1 + b){
                    dis[x][a].u = c - d;
                    dis[x][a].d = dis[u][maxn].d + 1 + b;
                    q.push({x, a, dis[x][a].d, dis[x][a].u});
                }
                else if(dis[x][a].d == dis[u][maxn].d + 1 + b && dis[x][a].u < c - d){
                    dis[x][a].d = dis[u][maxn].d + 1 + b;
                    dis[x][a].u = c - d;
                    q.push({x, a, dis[x][a].d, dis[x][a].u});
                }
            }
            
        }
    }
    int res = inf;
    for(int i = 1; i <= n * n; i++){
        res = min(res, dis[n * n][i].d);
    }
    return res;
}
signed main(){
    IOS;
    cin >> n;
    for(int i = 1; i <= n * n; i++){
        for(int j = 1; j <= n * n; j++){
            dis[i][j].d = inf;
            dis[i][j].u = -inf;
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            int u = (i - 1) * n + j;
            int a;
            cin >> a;
            P[u] = a;
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j < n; j++){
            int u = (i - 1) * n + j;
            int a;
            cin >> a;
            v[u].push_back({u + 1, a});
        }
    }
    for(int i = 1; i < n; i++){
        for(int j = 1; j <= n; j++){
            int u = (i - 1) * n + j;
            int a;
            cin >> a;
            v[u].push_back({u + n, a});
        }
    }
    cout << solve();
	return 0;
}
posted @ 2024-03-11 12:36  mostimali  阅读(20)  评论(0编辑  收藏  举报