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