【LGR-196-Div.4】洛谷入门赛 #26 题A - H 详细题解--优化思路简洁代码(C++,Python语言描述)

前言:

        觉得这个比赛很有意思的,都是暴力题,涉及一些细节,难度比较适合刚学编程语言的,可以很好的锻炼基础还有手速,最后两题也是比较有意思,之后也准备更新atc的比赛题解和洛谷的一些高质量比赛题解(算法网瘾就是想参加各种比赛)

      如果觉得有帮助,或者觉得我写的好,可以点个赞或关注,也可以看看我的一些其他文章,我之后也会更新一些基础算法详细解释

比赛链接:

【LGR-196-Div.4】洛谷入门赛 #26 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

目录

题A:

题目大意和解题思路:

代码(C++):

代码(Python):

题B:

题目大意和解题思路:

代码(C++):

代码(Python):

题C:

题目大意和解题思路:

代码(C++):

代码(Python):

题D:

题目大意和解题思路:

代码(C++):

代码(Python):

题E:

题目大意和解题思路:

代码(C++):

代码(Python):

题F:

题目大意和解题思路:

代码(C++):

代码(Python):

题G:

题目大意和解题思路:

代码(C++):

代码(Python):

题H:

题目大意和解题思路:

代码(C++):

代码(Python):


题A:

B4017 [语言月赛 202408] 相识于 2016 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意和解题思路:

2018年8月是认识的第一个月,现在输入年和月,问认识了几个月

不需要管理月份大小的,只要月份小于8,那么表示肯定不是同一年

需要注意的是8月是第一个月,也就是7月是第0个月,减7就可以了

所以res = (x - 2016) * 12 + (y - 7) 

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int x, y;
    std::cin >> x >> y;
    int res = (x - 2016) * 12 + (y - 8) + 1;
    std::cout << res << std::endl;
}

代码(Python):

def main():
    x, y = map(int, input().split())
    res = (x - 2016) * 12 + (y - 7)
    print(res)

题B:

B4018 [语言月赛 202408] 游戏与共同语言 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意和解题思路:

  • 胜局数者排名靠前
  • 若胜局数相同,净胜数者排名靠前
  • 若净胜数仍相同,平局记录者排名靠前
  • 不存在平局记录仍相同的情况

简单的判断就行,一个一个写就不会出错了

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int wa, ca, ta, wb, cb, tb;
    std::cin >> wa >> ca >> ta >> wb >> cb >> tb;
    bool f = 0;
    if (wa == wb) {
        if (ca == cb) {
            if (ta > tb) {
                f = 1;
            } else {
                f = 0;
            }
        } else if (ca > cb) {
            f = 1;
        } else {
            f = 0;
        }
    } else if (wa > wb) {
        f = 1;
    } else {
        f = 0;
    }
    if (f) {
        std::cout << "A" << std::endl;
    } else {
        std::cout << "B" << std::endl;
    }
}

代码(Python):

def main():
    wa, ca, ta = map(int, input().split())
    wb, cb, tb = map(int, input().split())
    f = 0
    if wa == wb:
        if ca == cb:
            if ta > tb:
                f = 1
            else:
                f = 0
        elif ca > cb:
            f = 1
        else:
            f = 0
    elif wa > wb:
        f = 1
    else:
        f = 0
    if f == 1:
        print("A")
    else:
        print("B")

题C:

B4019 [语言月赛 202408] 皆与生物有缘 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意和解题思路:

本题就是求两名老师评分总分的平均值,向上取整

向上取整,加上除数减一就行了,这里的除数是2,那么就在总数上加一

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n, x1 = 0, x2 = 0;
    std::cin >> n;
    int x;
    for (int i = 0; i < n; i++) {
        std::cin >> x;
        x1 += x;
    }
    for (int i = 0; i < n; i++) {
        std::cin >> x;
        x2 += x;
    }
    int res = (x1 + x2 + 1) / 2;
    std::cout << res << std::endl;
}

代码(Python):

def main():
    n = int(input())
    a1 = list(map(int, input().split()))
    a2 = list(map(int, input().split()))
    res = (sum(a1) + sum(a2) + 1) // 2
    print(res)

题D:

B4020 [语言月赛 202408] 两座城市的 543 千米 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意和解题思路:

果一列高铁先经过 a,再经过 b,则称其为一列由 a 市直达 b 市的高铁

现在,给出所有高铁列车的信息,请问一共有多少列由 a 市直达 b 市的高铁

输入的第一行为四个整数 N,M,a,b。

接下来 M 行,每行的第一个整数为 l​,接下来输入 l 个数

保证同一次高铁不会重复停靠某座城市

这题的意思就是找一列数字中,是否先出现a,然后出现b,定义一个bool变量f然后遍历数组就行了,然后找到a,就把f变成1,继续遍历,当f == 1且找到b的时候,那么这个就是符合条件的

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n, m, a, b;
    std::cin >> n >> m >> a >> b;
    int res = 0;
    for (int i = 0; i < m; i++) {
        int len;
        std::cin >> len;
        bool f = 0;
        for (int j = 0; j < len; j++) {
            int x;
            std::cin >> x;
            if (x == a) {
                f = 1;
            }
            if (f == 1 && x == b) {
                res += 1;
            }
        }
    }
    std::cout << res << std::endl;
}

代码(Python):

def main():
    n, m, a, b = map(int, input().split())
    res = 0
    for _ in range(m):
        arr = list(map(int, input().split()))
        f = 0
        for i in range(1, len(arr)):
            x = arr[i]
            if x == a:
                f = 1
            if f == 1 and x == b:
                res += 1
    print(res)

题E:

B4021 [语言月赛 202408] 于抑郁中支持 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意和解题思路:

那是一段混沌的时期,风的记忆裂变为 n 块碎片,第 i 块的特征值为 ai。

定义整数 x 的后 p 位的值为 x mod 10^p。特征值后 t 位相同的记忆碎片,从属于同一事件。

请问,n 块碎片共从属于多少不同的事件

这题就是阅读理解吧,特征值后t位,那就是 x  mod 10 ^ t
把每一个数字x 的x mod 10 ^ t 求出来,然后看有哪些不同

可以把求出来的值放入一个set(),最后输出这个set的长度就行了

t <= 4 ,10 ^ 4也不需要用long long

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n, t;
    std::cin >> n >> t;
    int mod = std::pow(10, t);
    std::unordered_set<int> has;
    for (int i = 0; i < n; i++) {
        int x;
        std::cin >> x;
        int a = x % mod;
        has.insert(a);
    }
    std::cout << has.size() << std::endl;
}

代码(Python):

def main():
    n, t = map(int, input().split())
    mod = 10 ** t
    arr = list(map(int, input().split()))
    has = set()
    for i in range(len(arr)):
        a = arr[i] % mod
        has.add(a)
    print(len(has))

题F:

B4022 [语言月赛 202408] 蓝色的网易云 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意和解题思路:

风的歌单中共有 n 首歌,这些歌曲可以根据题材分为 m 类,第 i 首歌的题材为 ci​。风聆并不偏好任何一种题材,因此歌单中各题材的歌曲数量相同。

现在,请你给出一个歌曲播放顺序,使得相邻播放的歌曲题材不相同。

就是说数字表示这首歌的题材,现在需要一个播放的顺序,保证相邻的题材不同

然后歌单中各种题材的歌曲数量相同,这个条件很关键,如果没有这个条件那就是比较复杂的贪心了

歌单中各种题材的歌曲数量相同,那么对于每一种歌曲,取一首歌,排成一列,然后同样的方式把歌曲取完就行

比如题目中的示例:

1 1 2 2 3 3
先取1 2 3 排列, 然后再取1 2 3 ,最后的排列就是1 2 3 1 2 3

注意题目中输出的是歌曲的编号,而且是从1开始

可以定义一个m行的二维数组,每一行都表示一种歌曲题材

然后把歌曲存储进去,输出的时候就是每一列取一个数字输出即可

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n, m;
    std::cin >> n >> m;
    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
    std::vector<std::vector<int>> b(m, std::vector<int>());
    for (int i = 0; i < n; i++) {
        b[a[i] - 1].push_back(i + 1);
    }
    //遍历列,由于歌单中各种题材的歌曲数量相同,那么一个题材歌曲数量就是n / m
    for (int i = 0; i < n / m; i++) {
        //遍历行
        for (int j = 0; j < m; j++) {
            std::cout << b[j][i] << std::endl;
        }
    }
}

代码(Python):

def main():
    n, m = map(int, input().split())
    a = list(map(int, input().split()))
    b = [[] for _ in range(m)]
    for i in range(n):
        b[a[i] - 1].append(i + 1)
    for i in range(n // m):
        for j in range(m):
            print(b[j][i])

题G:

B4023 [语言月赛 202408] 因友情而终结 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

好恶心的字符串题目

题目大意和解题思路:

字符串 S 是一个仅由英文小写字母构成的串。现在,你可以对字符串 S 执行任意次如下操作:

  • 选择 S 长度为 4 的一个子串,将其替换为 love

请问,至少操作多少次,字符串 S 不再有子串 friend

定义:子串指的是一个字符串中连续的一段字符序列。例如,字符串 aabbcc 有子串 aabaabb,但 abc 不是字符串 aabbcc 的子串,因为其不连续。

开始我没想太多,觉得friend的数量就是答案

但其实不是,如果两个"friend"字符之间的距离小于3,那一个love就可以消除两个friend

从字符d开始替换成love即可

比如friendaafriend - > frienloveriend

我直接kmp

10^6的数据量,肯定不能直接替换的,可以先找出每个friend的起始位置,把位置放在一个数组中

然后遍历这个数组

看两个位置之间相差是否小于9,如果不小于9,那么这两个字符串就只需要一次操作就可以完成

具体看代码(有简单注释)

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::string s;
    std::cin >> s;
    //存放位置的数组
    std::vector<int> pos;
    std::string target = "friend";
    int p = s.find(target);
    //当找不到的时候跳出循环
    while (p != std::string::npos) {
        pos.push_back(p);
        //从此位置后6位再开始找
        p = s.find(target, p + 6);
    }
    int res = 0;
    //循环
    for (int i = 0; i < pos.size(); i++) {
        res++;
        //上一个位置
        int last = pos[i];
        //如果两个位置直接相差小于9,那么表示这两个friend可以一个love替换
        //然后i++,表示跳过下一个循环
        while (i + 1 < pos.size() && pos[i + 1] < last + 9) {
            i++;
        }
    }
    std::cout << res << std::endl;
}

代码(Python):

def main():
    s = input()
    #存放位置的数组
    pos = []
    target = "friend"
    p = s.find(target)
    #当找不到的时候跳出循环
    while p != -1:
        pos.append(p)
        #从此位置后6位再开始找
        p = s.find(target, p + 6)
    res, i = 0, 0
    while i < len(pos):
        res += 1
        #上一个位置
        last = pos[i]
        #如果两个位置直接相差小于9,那么表示这两个friend可以一个love替换
        #然后i++,表示跳过下一个循环
        while i + 1 < len(pos) and pos[i + 1] < last + 9:
            i += 1
        i += 1
    print(res)

题H:

B4024 [语言月赛 202408] 保持连接的方式 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这题我说实话,就是烦人,没啥技巧,模拟就行了

题目大意和解题思路:

就是一个盒子,有m * n 个格子,每个格子最多只能放k个日记

然后每天写的日记放在某一格(从1开始计数)

如果这个格子满了,就取出最早放进去的日记销毁,然后输出此时销毁的日记编号和移动的日记数目

如果没满,就输出-1

比如示例:

输入

2 2 3 5
3 1 1
4 1 1
2 1 1
5 1 1
1 1 1

输出

-1
-1
-1
2 0
3 2

k为3,一个格子最多放3个,3进入(1, 1),4进入(1, 1), 2进入(1, 1)都不会满,输出-1

然后5进入满了,此时(1, 1)中编号最小的是2,需要移动0次,输出(2, 0)

1进入,移除3,需要移动2个
 

直接用一个哈希表模拟就行了

当哈希表此时的键对应的值小于k的时候,就输出-1

大于k的时候,就在里面找最小值的下标即可,输出下标

注意输入进来的x,y需要减一的操作

代码(C++):

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n, m, k, t;
    std::cin >> n >> m >> k >> t;
    std::map<std::pair<int, int>, std::vector<int>> has;
    for (int i = 0; i < t; i++) {
        int a, x, y;
        std::cin >> a >> x >> y;
        x--; y--;
        auto key = std::make_pair(x, y);
        if (has[key].size() < k) {
            has[key].push_back(a);
            std::cout << -1 << std::endl;
        } else {
            int mn = *std::min_element(has[key].begin(), has[key].end());
            auto it = std::find(has[key].begin(), has[key].end(), mn);
            int move = has[key].size() - (it - has[key].begin()) - 1;
            has[key].erase(it);
            has[key].push_back(a);
            std::cout << mn << " " << move << std::endl;
        }
    }
    return 0;
}

代码(Python):

def main():
    n, m, k, t = map(int, input().split())
    has = defaultdict(list)

    res = []
    
    for _ in range(t):
        a, x, y = map(int, input().split())
        x -= 1
        y -= 1
        if len(has[(x, y)]) < k:
            has[(x, y)].append(a)
            res.append(-1)
        else:
            mn = min(has[(x, y)])
            i = has[(x, y)].index(mn)
            move = len(has[(x, y)]) - i - 1

            has[(x, y)].pop(i)
            has[(x, y)].append(a)
            res.append(f"{mn} {move}")
    print("\n".join(map(str, res)))

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值