2024 CSP-J 题解

2024 CSP-J题解

扑克牌

​ 题目给出了一整套牌的定义,但是纯粹在扯淡,完全没有必要去判断给出的牌的花色和点数,我们用一个循环来依次读入每一张牌,如果这个牌在之前出现过,我们就让答案减一。这里建议用map、unordered_set或者给每一种牌一个编号,然后用数组存储也可以。

#include <bits/stdc++.h>

using namespace std;

int n;

int main()
{
    map<string, bool> M;
    int ans = 52;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        string tmp;
        cin >> tmp;
        if (!M[tmp])
            ans--, M[tmp] = 1;
    }
    cout << ans;
    return 0;
}

地图探险

​ 纯粹的记忆化搜索,用数组存储对于每一个方向下一步坐标的差值,每次要执行移动操作之前,我们都要不停地执行右转的操作,直到下一步的坐标合法为止。

​ 我们可以开辟一个二维数组来记录每一次搜索经过的位置,每次走到一个之前没走过的位置,我们就让答案加一。

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e3 + 5;
int mx[4] = {0, 1, 0, -1}, my[4] = {1, 0, -1, 0}, ans; // mx 和 my 用来存储每一个方向对应的变化值
char Map[maxn][maxn];                                  // 储存整个地图
bool vis[maxn][maxn];                                  // 记录每个地方都有没有被遍历过
int n, m, k, x_0, y_0, d;

void dfs(int x, int y, int d)
{
    if (!vis[x][y]) // 如果这个位置还没有走过,就让答案加一
        ans++;
    vis[x][y] = 1;
    int X = x + mx[d], Y = y + my[d];                                   // 下一步要走的位置
    while ((X < 1 || X > n || Y < 1 || Y > m || Map[X][Y] == 'x') && k) // 下一步不合法,并且还需要执行操作,那么我们右转
        d = (d + 1) % 4, k--, X = x + mx[d], Y = y + my[d];             // k 一定要减一
    if (k == 0)                                                         // 后面没有操作要进行了
        return;
    k--;
    dfs(X, Y, d); // 移动到下一步
}

void solve()
{
    cin >> n >> m >> k;
    cin >> x_0 >> y_0 >> d;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> Map[i][j];
    dfs(x_0, y_0, d);
    cout << ans << '\n'; // 因为多组样例,这几行都是清空的操作
    ans = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            vis[i][j] = 0;
}

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

小木棍

​ 数学(dabiao)题,可以先简单找找规律。

​ 首先对于 0~9 每一种数字,如果要用火柴拼出来的话,他们分别需要 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 根木条。根据数据范围,我们可以得到一点提示,这题反正是跟 7 脱不了关系。

​ 其次有一个很显而易见的道理,因为 8 这个数字需要的火柴最多,整个数字的长度就越短,也就越小,那么当 n 是 7 的倍数时,那么 ( n / 7 ) (n / 7) (n/7) 个 8 组成的数字就是最小的。

除此之外:

如果 n % 7 = 1:

​ 因为一根火柴什么数字都拼不出来,所以需要去牺牲从前往后第二个数字来凑出一个数来(想不出来可以打表)。结果就是 10 + 很多个 8。

​ 但是需要特判 n = 1 的时候,结果是 -1。

如果 n % 7 = 2:

​ 两根火柴可以组成一个 1,后面全部填 8。

如果 n % 7 = 3:

​ 需要特判 n = 3 和 n = 10,答案分别是 7 和 22,其他情况,答案是 200 + 很多个 8。

如果 n % 7 = 4:

​ 特判 n = 4,答案是 4,其他情况答案是 20 + 很多个 8。

如果 n % 7 = 5:

​ 结果是 2 + 很多个 8。

如果 n % 7 = 6:

​ 结果是 6 + 很多个 8。

#include <bits/stdc++.h>

using namespace std;

int n, T;

int main()
{
    cin >> T;
    while (T--)
    {
        cin >> n;
        int type = n % 7;
        if (type == 0)
        {
            for (int i = 1; i <= n / 7; i++)
                cout << 8;
            cout << '\n';
            continue;
        }
        if (type == 1)
        {
            if (n == 1)
                cout << -1 << '\n';
            else
            {
                cout << 10;
                for (int i = 1; i <= n / 7 - 1; i++)
                    cout << 8;
                cout << '\n';
            }
            continue;
        }
        if (type == 2)
        {
            cout << 1;
            for (int i = 1; i <= n / 7; i++)
                cout << 8;
            cout << '\n';
            continue;
        }
        if (type == 3)
        {
            if (n == 3)
                cout << 7 << '\n';
            else if (n == 10)
                cout << 22 << '\n';
            else
            {
                cout << 200;
                for (int i = 1; i <= (n - 17) / 7; i++)
                    cout << 8;
                cout << '\n';
            }
            continue;
        }
        if (type == 4)
        {
            if (n == 4)
                cout << 4 << '\n';
            else
            {
                cout << 20;
                for (int i = 1; i <= (n - 11) / 7; i++)
                    cout << 8;
                cout << '\n';
            }
            continue;
        }
        if (type == 5)
        {
            cout << 2;
            for (int i = 1; i <= (n - 5) / 7; i++)
                cout << 8;
            cout << '\n';
            continue;
        }
        if (type == 6)
        {
            cout << 6;
            for (int i = 1; i <= (n - 6) / 7; i++)
                cout << 8;
            cout << '\n';
            continue;
        }
    }
    return 0;
}

​ 这种题目一般建议还是先打个表找找规律,或者直接写一个暴力看看比较小的数据点的答案。例如这个题目,可以先写一个 10 的某次方的暴搜,枚举每一位是多少。

接龙

​ 这里我没有想到特别简单的思路,要么就是空间不太正确,要么就是时间不太正确,目前的做法是 dp + 差分前缀和。

​ 我们预处理出 100 轮每一轮的答案,然后做个离线的输出,我们把所有的询问按照从小到大的顺序进行排序,因为预处理的时候我们是按照轮数从小到大的顺序进行 d p dp dp 的,所以我们直接把答案全部记录下来就可以。

​ 然后就是 d p dp dp 状态的设计,首先 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示第 i 轮以元素 j 为结尾的答案。但是这里因为第 i 轮的答案只与前一轮有关,所以我们可以把 d p dp dp 的前一个状态去掉,用两个 d p dp dp 数组轮流使用就可以了。

​ 因为在接龙的时候,当前这一轮的人不能和上一轮一样,所以我们重新设计一下状态, dp[j] 表示当前这一轮以元素 j 结尾。

d p [ j ] = − 2 dp[j] = -2 dp[j]=2:当前这一轮以 j 结尾,没人能完成接龙;

d p [ j ] = − 1 dp[j] = -1 dp[j]=1:当前这一轮以 j 结尾,有两个人能完成接龙,根据题意,如果有两个人能完成接龙(使用的句子开头和结尾相同),那么接龙就一定可以完成,所以我们只用考虑两个人的情况就可以了,两个人以上不用考虑;

d p [ j ] = i dp[j] = i dp[j]=i(i 大于 0):当前这一轮以 j 结尾,并且只有一个人能完成接龙,这个人的编号是 i i i

状态转移方程:

​ 对于每一个人 i 遍历所有的 S i , j S_{i,j} Si,j (第 i i i 个人的词库里面的第 j j j 个字符),当发现上一轮 d p [ S i , j ] dp[S_{i, j}] dp[Si,j] 不等于 − 2 -2 2 且不等于 i i i 的时候(连续的两轮不能是同一个人),说明这个数后面的 k 个元素,可以在当前这一轮作为的最后一个元素完成接龙,因为是连续的一个区间,所以这里我们使用差分来进行维护,然后我们再进行前缀和,这样就可以看出来有哪些元素可以完成接龙了(对于 i i i 这一个人来说),把找出来的元素的 d p dp dp 值赋成 i i i

​ 然后我们再去处理其他人,如果发现有一个元素已经被赋值了,说明有两个或者两个以上的人可以使用这个元素作为结尾完成这一轮接龙, d p dp dp 值就是 -1。

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

void solve()
{
    int n, k, q;
    cin >> n >> k >> q;
    vector<vector<int>> g(n); // 存储所有的 S
    vector<int> len(n); // 每个 S 对应的长度
    int maxn = -1;
    bool flag = false; // 如果没有 1,说明完全没有可能接龙,直接寄
    for (int i = 0; i < n; i += 1)
    {
        cin >> len[i];
        g[i].resize(len[i]);
        for (int j = 0; j < len[i]; j += 1)
        {
            cin >> g[i][j];
            maxn = max(maxn, g[i][j] + 1);
            if (g[i][j] == 1 && j != len[i] - 1)
                flag = true;
        }
    }
    vector<tuple<int, int, int>> a(q); // 储存询问
    int idx = 0, ma = 0;
    for (auto &[r, c, id] : a)
    {
        cin >> r >> c;
        ma = max(ma, r);
        id = idx++;
    }
    idx = 0;
    sort(a.begin(), a.end()); // 按照轮数从小到大的顺序排列
    vector<int> ans(q); // 答案
    vector<int> dp(maxn, -2); // 先全部赋值成 -2,表示不能以 j 为结尾完成这一轮
    dp[1] = -1;
    vector<int> now(200000); // 差分数组
    for (int round = 1; round <= ma && flag; round += 1)
    {
        vector<int> dp1(maxn, -2); // 当前这一轮的 dp 值
        for (int i = 0; i < n; i += 1) // 枚举第几个人
        {
            for (int j = 0; j < len[i]; j++) // 初始化
                now[j] = 0;
            for (int j = 0; j < len[i] - 1; j += 1) 
            {
                int x = g[i][j];
                if (dp[x] != -2 && dp[x] != i) // dp 是上一轮的结果,如果 x 可以作为接龙的结尾,那么后面 k 个也可以 
                {
                    int to = j + k; // 差分
                    now[j + 1] += 1;
                    if (to < len[i])
                        now[to] -= 1;
                }
            }
            for (int j = 1; j < len[i]; j += 1)
            {
                int x = g[i][j];
                now[j] += now[j - 1]; // 前缀和
                if (now[j] != 0 && dp1[x] != -1) // 如果这个数字被差分标记了并且没有两个以上的人标记了这个元素(如果是 -1 就不用管了)
                {
                    if (dp1[x] == -2)
                        dp1[x] = i;
                    else if (dp1[x] != i) // 已经有别人标记过了
                        dp1[x] = -1;
                }
            }
        }
        while (idx < q) // 给每一个询问提供一个答案
        {
            auto &[r, c, id] = a[idx];
            if (r != round)
                break;
            else
            {
                if (c >= maxn || dp1[c] == -2)
                    ans[id] = 0;
                else
                    ans[id] = 1;
                idx += 1;
            }
        }
        dp = dp1;
    }

    for (int i = 0; i < q; i += 1) // 离线输出结果
        cout << ans[i] << "\n";
}
int main()
{   
    ios::sync_with_stdio(0); // 怕被卡,关流一下 
    cin.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }

    return 0;
}




作者能力有限,如果有任何错误之处,还请各位指教。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/905432.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis新数据类型

新数据类型 Bitmaps 命令 setbit 实例 getbit 实例 bitcount 实例 bitop 实例 Bitmaps与set 对比 HyperLogLog 命令 pfadd 实例 pfcount 实例 pfmerge 实例 Geospatial 命令 geoadd 实例 geopos 实例 geodist 实例 georadius 实例 Bitmaps Ⅰ.B…

【Qt】QTableView添加下拉框过滤条件

实现通过带复选框的下拉框来为表格添加过滤条件 带复选框的下拉框 .h文件 #pragma once #include <QCheckBox> #include <QComboBox> #include <QEvent> #include <QLineEdit> #include <QListWidget>class TableComboBox : public QComboBox …

Java Executor ScheduledExecutorService 源码

前言 相关系列 《Java & Executor & 目录》《Java & Executor & ScheduledExecutorService & 源码》《Java & Executor & ScheduledExecutorService & 总结》《Java & Executor & ScheduledExecutorService & 问题》 涉及内容 …

C++:继承~派生类以及衍生的多继承与菱形继承问题

C中的继承其实是一个C中的坑,主要体现在其多继承(菱形继承)方面,我们先来了解下继承的概念 一,继承的概念与定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许我们在保持原有类特性的基础上进行扩展&#xff0c;增…

Python 从入门到实战43(Pandas数据结构)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;可以熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们学习了NumPy数组操作的相关基础知识。今天学习一下pa…

工程项目智能化管理平台,SpringBoot框架智慧工地源码,实现工程建设施工可视化、智能化的全过程闭环管理。

智慧工地管理系统的建设以“1个可扩展性平台2个应用端3方数据融合N个智能设备”为原则。以“智、保、安、全”为导向&#xff0c;与工程建设管理信息系统、综合安防平台深度集成&#xff0c;构建统一的标准化工地平台&#xff0c;实现现场人员、车辆、项目、安全、进度等方面的…

使用React构建现代Web应用

&#x1f496; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4bb; Gitee主页&#xff1a;瑕疵的gitee主页 &#x1f680; 文章专栏&#xff1a;《热点资讯》 使用React构建现代Web应用 1 引言 2 React简介 3 安装React 4 创建React项目 5 设计应用结构 6 创建组件 7 使用组件…

哈希——哈希表处理哈希冲突的方法

处理哈希冲突 实践中哈希表⼀般还是选择除法散列法作为哈希函数。 当然哈希表无论选择什么哈希函数也避免不了冲突&#xff08;主要作用就是减少冲突&#xff09;&#xff0c;那么插入数据时&#xff0c;如何解决冲突呢&#xff1f;主要有两种两种方法&#xff0c;开放定址法和…

海外云手机是什么?对外贸电商有什么帮助?

在外贸电商领域&#xff0c;流量引流已成为卖家们关注的核心问题。越来越多的卖家开始利用海外云手机&#xff0c;通过TikTok等社交平台吸引流量&#xff0c;以推动商品在海外市场的销售。那么&#xff0c;海外云手机到底是什么&#xff1f;它又能为外贸电商卖家提供哪些支持呢…

Hadoop-001-本地虚拟机环境搭建

一、安装VMware 官方下载VMware&#xff1a; https://vmware.mdsoft.top/?bd_vid5754305114651491003 二、下载镜像文件 阿里云镜像仓库&#xff1a; https://mirrors.aliyun.com/centos/ 本文档使用 CentOS-7-x86_64-DVD-1810-7.6.iso 搭建虚拟机 三、搭建虚拟机 1、编辑…

Oracle视频基础1.1.2练习

1.1.2 需求&#xff1a; 查询oracle组件和粒度大小&#xff0c; select component,granule_size from v$sga_dynamic_components;Oracle SGA 中组件和粒度大小查询详解 在 Oracle 数据库的内存结构中&#xff0c;SGA&#xff08;System Global Area&#xff0c;系统全局区&am…

动态上下文信念(DCB)

DCB&#xff08;动态上下文信念&#xff09;是一个用于累积通过注视获得信息的状态表示组件。它由三个部分组成&#xff1a; Fovea&#xff08;中央凹&#xff09;&#xff1a;接收来自注视位置周围区域的高分辨率视觉输入。Contextual beliefs&#xff08;上下文信念&#xf…

双月生日会:温暖相聚,共庆美好时刻

亲爱的华清远见西安中心的家人们&#xff1a; &#x1f389;&#x1f382; 在这金风送爽的秋日里&#xff0c;我们迎来了9、10月的生日会。在这个特别的日子里&#xff0c;我们聚集一堂&#xff0c;共同庆祝那些在这两个月份里出生的小伙伴们的生日。&#x1f382; 活动现场布…

Junit + Mockito保姆级集成测试实践

一、做好单测&#xff0c;慢即是快 对于单元测试的看法&#xff0c;业界同仁理解多有不同&#xff0c;尤其是在业务变化快速的互联网行业&#xff0c;通常的问题主要有&#xff0c;必须要做吗&#xff1f;做到多少合适&#xff1f;现在没做不也挺好的吗&#xff1f;甚至一些大…

【经典论文阅读11】ESMM模型——基于贝叶斯公式的CVR预估

传统的CVR模型&#xff08;也就是直接对conversion rate建模的模型&#xff09;在实际应用中面临两个问题&#xff08;样本选择偏差与数据稀疏性问题&#xff09;。为了解决这两个问题&#xff0c;本文提出ESMM模型。该模型巧妙地利用用户行为序列去建模这个问题&#xff0c;从…

使用Git进行版本控制的最佳实践

文章目录 Git简介基本概念仓库&#xff08;Repository&#xff09;提交&#xff08;Commit&#xff09;分支&#xff08;Branching&#xff09; 常用命令初始化仓库添加文件提交修改查看状态克隆仓库分支操作合并分支推送更改 最佳实践使用有意义的提交信息定期推送至远程仓库使…

Vision-Language Models for Vision Tasks: A Survey阅读笔记

虽然LLM的文章还没都看完&#xff0c;但是终究是开始看起来了VLM&#xff0c;首当其冲&#xff0c;当然是做一片文献综述啦。这篇文章比较早了&#xff0c;2024年2月份出的last version。 文章链接&#xff1a;https://arxiv.org/abs/2304.00685 GitHub链接&#xff1a;GitHu…

Oracle OCP认证考试考点详解082系列07

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 31. 第31题&#xff1a; 题目 解析及答案&#xff1a; 关于 “SET VERIFY ON” 命令&#xff0c;以下哪两个陈述是正确的&#xff1f; A…

网络搜索引擎Shodan(7)完结

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 声明&#xff1a;本文主要用作技术分享&#xff0c;所有内容仅供参考。任何使用或依赖于本文信息所造成的法律后果均与本人无关。请读者自行判断风险&#xff0c;并遵循相关法律法规。 感谢泷…

【C++ 算法进阶】算法提升八

复杂计算 &#xff08;括号问题相关递归套路 重要&#xff09; 题目 给定一个字符串str str表示一个公式 公式里面可能有整数 - * / 符号以及左右括号 返回最终计算的结果 题目分析 本题的难点主要在于可能会有很多的括号 而我们直接模拟现实中的算法的话code会难写 要考虑…