当前位置: 首页 > news >正文

AtCoderABC387题解

A题

链接

题目大意:给你AB,求$ ( A+B ) ^ 2 $,直接上代码!

#include<iostream>
using namespace std;

signed main() {
	int a,b;
	cin>>a>>b;
	cout<<(a+b)*(a+b);
	return 0;
}

B题

链接

给你一个列表,第$ i $行第$ j $列的值是$ij$,满足$ i ,j \le 9$,让你求这个列表中不等于$n$的数字之和。

因为数很小,根本不用优化,上代码!!!

#include<iostream>
using namespace std;
#define fo(i,begin,end) for(int i=begin;i<=end;i++)
signed main() {
	int n;
	cin>>n;
	int ans=0;
	fo(i,1,9) {
		fo(j,1,9) {
			if(i*j!=n){
				ans+=i*j;
			}
		}
	}
	cout<<ans;
	return 0;
}

C题

链接

有点难:

给你区间,求蛇形数的数量。

当区间 [L, R] 非常大时,直接模拟遍历区间内的每个数来判断是否为蛇形数会导致时间复杂度很高,可能会超时。我们可以使用数位 DP(动态规划)的方法来解决这个问题。

数位 DP 是一种针对数字的每一位进行动态规划的算法,通常用于解决与数字的数位特征相关的计数问题。对于本题,我们可以通过数位 DP 来计算小于等于某个数 x 的蛇形数的数量,然后用小于等于 R 的蛇形数数量减去小于等于 L - 1 的蛇形数数量,就可以得到区间 [L, R] 内的蛇形数数量。

上代码!!!

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
using namespace std;

// 数位DP数组,dp[pos][limit][first][maxDigit] 表示处理到第pos位,是否受到上界限制,是否是首位,之前的最大数字
long long dp[20][2][2][10];

// 数位DP函数
long long dfs(int pos, bool limit, bool first, int maxDigit, const string& num) {
    if (pos == num.length()) return first ? 0 : 1;
    if (dp[pos][limit][first][maxDigit] != -1) return dp[pos][limit][first][maxDigit];
    int up = limit ? num[pos] - '0' : 9;
    long long ans = 0;
    for (int i = 0; i <= up; i++) {
        if (first) {
            if (i == 0) {
                ans += dfs(pos + 1, limit && i == up, true, 0, num);
            } else {
                ans += dfs(pos + 1, limit && i == up, false, i, num);
            }
        } else {
            if (i < maxDigit) {
                ans += dfs(pos + 1, limit && i == up, false, maxDigit, num);
            }
        }
    }
    return dp[pos][limit][first][maxDigit] = ans;
}

// 计算小于等于x的蛇形数的数量
long long solve(const string& x) {
    memset(dp, -1, sizeof(dp));
    return dfs(0, true, true, 0, x);
}

int main() {
    string L, R;
    cin >> L >> R;
    // 将L减1
    int i = L.length() - 1;
    while (i >= 0 && L[i] == '0') {
        L[i] = '9';
        i--;
    }
    L[i]--;
    // 计算结果
    long long ans = solve(R) - solve(L);
    cout << ans << endl;
    return 0;
}    

D题

链接

#include <iostream>
#include <vector>
#include <queue>
#include <utility>
using namespace std;

const int INF = 1e9;
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};

struct State {
    int x, y;
    bool isVertical;
    int steps;
};

int main() {
    int H, W;
    cin >> H >> W;
    vector<string> grid(H);
    pair<int, int> start, goal;

    for (int i = 0; i < H; ++i) {
        cin >> grid[i];
        for (int j = 0; j < W; ++j) {
            if (grid[i][j] == 'S') start = {i, j};
            if (grid[i][j] == 'G') goal = {i, j};
        }
    }

    vector<vector<vector<int>>> dist(H, vector<vector<int>>(W, vector<int>(2, INF)));
    queue<State> q;

    // 初始状态入队,分别考虑第一次垂直和水平移动
    q.push({start.first, start.second, true, 0});
    q.push({start.first, start.second, false, 0});
    dist[start.first][start.second][0] = dist[start.first][start.second][1] = 0;

    while (!q.empty()) {
        State cur = q.front();
        q.pop();

        if (cur.x == goal.first && cur.y == goal.second) {
            cout << cur.steps << endl;
            return 0;
        }

        for (int i = 0; i < 4; ++i) {
            if ((cur.isVertical && (i < 2)) || (!cur.isVertical && (i >= 2))) continue;

            int nx = cur.x + dx[i];
            int ny = cur.y + dy[i];

            if (nx >= 0 && nx < H && ny >= 0 && ny < W && grid[nx][ny] != '#') {
                int newSteps = cur.steps + 1;
                bool newIsVertical =!cur.isVertical;

                if (newSteps < dist[nx][ny][newIsVertical? 1 : 0]) {
                    dist[nx][ny][newIsVertical? 1 : 0] = newSteps;
                    q.push({nx, ny, newIsVertical, newSteps});
                }
            }
        }
    }

    cout << -1 << endl;
    return 0;
}    
  1. 状态表示

    • 我们将网格中的每个位置视为一个状态,同时考虑到移动的规则(横竖交替),每个状态还需要记录当前移动是垂直方向还是水平方向。因此,我们定义一个 State 结构体来表示状态,包含位置信息 (x, y)(其中 x 表示行,y 表示列)、移动方向信息 isVertical(布尔值,true 表示垂直移动,false 表示水平移动)以及已经走过的步数 steps
    • 为了记录从起点到每个位置在不同移动方向状态下的最短步数,我们使用一个三维数组 dist[H][W][2],其中 dist[x][y][0] 表示到达位置 (x, y) 时最后一步是水平移动的最短步数,dist[x][y][1] 表示到达位置 (x, y) 时最后一步是垂直移动的最短步数。初始时,将所有位置的步数设置为无穷大(这里用 1e9 表示),起点的两种状态(第一次垂直移动和第一次水平移动)的步数设置为 0。
  2. 广度优先搜索(BFS)的运用

    • BFS 是一种用于在图或网格中寻找最短路径的常用算法。在本题中,我们将网格看作一个图,每个单元格是图中的一个节点,相邻的单元格(通过边相连)之间有边连接。
    • 初始化一个队列 q,并将起点的两种初始状态(第一次垂直移动和第一次水平移动)加入队列。
    • 进入 BFS 的主循环,只要队列不为空,就取出队首的状态 cur
    • 检查当前状态 cur 的位置是否为目标位置。如果是,说明已经找到了从起点到终点的路径,此时输出 cur.steps(即当前路径的步数)并结束程序。
    • 否则,遍历四个方向(上、下、左、右,分别对应 dx 和 dy 数组中的偏移量)。根据当前状态 cur 的移动方向 isVertical,如果当前是垂直移动(isVertical 为 true),则跳过水平方向的移动(即 i < 2 的情况);反之,如果当前是水平移动(isVertical 为 false),则跳过垂直方向的移动(即 i >= 2 的情况)。这样就保证了移动是横竖交替的。
    • 计算新的位置 (nx, ny),如果新位置在网格范围内(nx >= 0 && nx < H && ny >= 0 && ny < W)且不是障碍物(grid[nx][ny] != '#'),则计算新的步数 newSteps = cur.steps + 1,并得到新的移动方向 newIsVertical =!cur.isVertical(因为移动方向要交替)。
    • 检查新的步数 newSteps 是否小于当前记录的到达位置 (nx, ny) 在新移动方向状态下的最短步数(dist[nx][ny][newIsVertical? 1 : 0])。如果是,更新 dist 数组,并将新的状态 {nx, ny, newIsVertical, newSteps} 加入队列 q
  3. 结果判断与输出

    • 如果 BFS 循环结束后,队列为空但还没有找到目标位置,说明从起点无法按照规则到达终点,此时输出 -1。

相关文章:

  • Java复习
  • 透析Vue的nextTick原理
  • tryhackme——Password Attacks
  • 考研c语言复习之栈
  • CMS网站模板定制设计与安全评估
  • 基于CAMEL 的Workforce 实现多智能体协同工作系统
  • Guava:Google开源的Java工具库,太强大了
  • ZCS的随机游走的题解
  • 用Llama 3微调私有知识库:本地部署避坑指南
  • 大屏技术汇集【目录】
  • CMake 函数和宏
  • 34-三数之和
  • 应用案例 | 核能工业:M-PM助力核工业科研项目
  • 华为网路设备学习-16 虚拟路由器冗余协议(VRRP)
  • vue设置自定义logo跟标题
  • 基于ISO 26262的汽车芯片认证流程解读
  • 使用PlotNeuralNet绘制ResNet50模型
  • 第十五次CCF-CSP认证(含C++源码)
  • VC6.0图文安装教程
  • NFT在艺术品市场的影响:面纵花魄还是一场夢?
  • 梵蒂冈选出新教皇,外交部:望新教皇推动中梵关系不断改善
  • 代理销售保险存在误导行为,农业银行重庆市分行相关负责人被罚款0.1万元
  • 海南省三亚市委原常委、秘书长黄兴武被“双开”
  • 美众议院通过法案将“墨西哥湾”更名为“美国湾”
  • 铲屎官花5万带猫狗旅行,宠旅生意有多赚?
  • 习近平抵达莫斯科对俄罗斯进行国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典