【NC23036】华华听月月唱歌

本文介绍了如何使用贪心策略解决区间合并问题,强调了先按左端点排序,再根据特定条件调整顺序以找到最优区间的技巧。通过C语言代码展示了如何实现这一算法。
摘要由CSDN通过智能技术生成

题目

华华听月月唱歌

区间合并(注意边界),贪心

思路

贪心的区间合并

因为是区间合并,所以我们先将区间从小到大排序,以方便合并,排序的时候还是按照区间左端点从小到大排序就行了。排好序之后我们得到类似下面这样的区间段:
在这里插入图片描述

由于只是按左端点从小到大排序,所以当左端点相同时,右端点不一定会有序

怎么贪心呢?

首先先找第一个“最优”的区间 a a a,即左端点最小时右端点最大的区间,并记录右端点的值 r r r,然后遍历 a a a 之后的区间,如果可以与 a a a 接上,则寻找这些能与 a a a 接上的所有区间中的最优区间(即右端点最大),然后更新 r r r 的值和答案值。

怎么寻找第一个最优区间?

可以知道的是,仅仅按左端点从小到大排序后,第一个区间并不一定是第一个最优区间,如上图(第二个才是),所以还得单独寻找第一个最优区间,这样代码显得臃肿。所以不如直接按“如果左端点不同,则按左端点从小到大排序,如果左端点相同,则按右端点从大到小排序”,这样的话,排好序之后的第一个区间一定是第一个最优区间。

在最后,如果所有区间都遍历完了,就看此时的 r r r 满不满足大于等于题目给定的 n n n,如果满足则说明应该返回答案,如果不满足则返回 − 1 -1 1。此外,在排好序之后还应该检查一下第一个区间左端点(即区间左端点的最小值)满不满足小于等于 1 1 1 的条件,如果最小的区间左端点都大于 1 1 1 了,那么说明再怎么也不能满足题意,直接返回 − 1 -1 1,就不用再进行后续操作了。

代码

#include <stdio.h>
#include <stdlib.h>

/**
 * @brief 自定义排序,以左端点从小到大排序,如果左端点相同则右端点从大到小排序
 *
 * @param a
 * @param b
 * @return int
 */
int cmp(const void* a, const void* b) {
    int(*aa)[2] = (int(*)[2])a;
    int(*bb)[2] = (int(*)[2])b;
    if ((*aa)[0] == (*bb)[0]) return (*bb)[1] - (*aa)[1];
    return (*aa)[0] - (*bb)[0];
}

int main(void) {
    int n = 0, m = 0;
    scanf("%d%d", &n, &m);
    int a[m][2], i = 0;
    for (; i < m; i++) {
        scanf("%d%d", &a[i][0], &a[i][1]);
    }
    qsort(a, m, sizeof(int[2]), cmp);
    // 注意题目的测试用例似乎没有包含最小的 L 大于 1
    // 的情况,所以下面这个判断可以不加,之后加不加就不知道了
    if (a[0][0] > 1) {
        printf("-1\n");
        return 0;
    }
    // 根据排序规则,我们可以知道排好序之后的第一个区间是最优的
    int ans = 1, r = a[0][1], t = r;
    i = 1;
    // 然后遍历其余区间
    while (i < m) {
        // 假设已经完成拼接或者已经不合法,则退出循环
        if (r == n || a[i][0] > r + 1) break;
        // 寻找下一段中最长的区间
        while (i < m && a[i][0] <= r + 1) {
            if (a[i][1] > t) t = a[i][1];
            i++;
        }
        // 更新区间右端点和答案
        r = t;
        ans++;
    }
    // 最后的答案根据最终拼接的区间右端点的大小确定
    printf("%d\n", r < n ? -1 : ans);
    return 0;
}
好的,这是一个比较简单的数学题,可以用矩阵快速幂求解。以下是 C++ 代码实现: ```c++ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 2; const int MOD = 1e9 + 7; struct Matrix { LL m[MAXN][MAXN]; Matrix() { memset(m, 0, sizeof(m)); } Matrix operator * (const Matrix& b) const { Matrix c; for (int i = 0; i < MAXN; ++i) { for (int j = 0; j < MAXN; ++j) { for (int k = 0; k < MAXN; ++k) { c.m[i][j] = (c.m[i][j] + m[i][k] * b.m[k][j]) % MOD; } } } return c; } } base, res; Matrix qpow(Matrix a, int b) { Matrix ans; for (int i = 0; i < MAXN; ++i) { ans.m[i][i] = 1; } while (b) { if (b & 1) { ans = ans * a; } a = a * a; b >>= 1; } return ans; } LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } int main() { LL a, b, n; cin >> a >> b >> n; if (n == 1) { cout << a << endl; } else if (n == 2) { cout << b << endl; } else { base.m[0][0] = base.m[0][1] = base.m[1][0] = 1; res = qpow(base, n - 2); LL ans = gcd(a * res.m[0][0] % MOD + b * res.m[1][0] % MOD, b * res.m[1][0] % MOD + b * res.m[1][1] % MOD); cout << ans << endl; } return 0; } ``` 在这段代码中,我们定义了一个 `Matrix` 结构体,它表示一个 $2\times2$ 的矩阵。其中重载了 `*` 运算符,实现了矩阵乘法。 然后,我们定义了一个矩阵快速幂函数 `qpow`,用于求解矩阵的 $n$ 次方。 最后,在 `main` 函数中,我们通过快速幂求出矩阵 $base$ 的 $n-2$ 次方,然后根据题目要求求出 $\gcd(F_N, F_{N+1})$ 并输出即可。 需要注意的是,当 $n=1$ 或 $n=2$ 时,直接输出 $a$ 或 $b$ 即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木又可可

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值