1 条题解

  • 0
    @ 2024-6-4 15:15:51

    由于只有10241024个时刻,考虑一个dp

    dpidp_i表示我刚刚在第ii个时刻喊了一句做核酸,且所有LiL\leq i的人都已经听到了喊声,我最少要喊多少句,同时用wayiway_i记录此时的方案数。

    那么,转移也就出来了: dpj=mini<j(dpi+1)dp_j=\min_{i<j}(dp_i+1)ii可以向jj转移当且仅当没有人的考察区间[L,R][L,R]满足i<LR<ji<L \leq R<j

    我们记录一个数组RiR_i,表示考察起点是ii的所有人,终点的最小值是多少。

    那么,上述条件等价于,mink=i+1j1Rkj\min_{k=i+1}^{j-1} R_k\geq j

    于是我们直接枚举每一个已经算出来的ii,然后枚举它能转移到的jj,在这个过程中动态的维护RR的最小值即可,时间复杂度O(10242+nO(1024^2)+n

    #include <bits/stdc++.h>
    #define ll long long
    #define T 1025
    #define maxn 1055
    #define mo 1000000007
    using namespace std;
    int n, l, r, R[maxn];
    ll dp[maxn], way[maxn];
    int main() {
        scanf("%d", &n);
        memset(R, 127, sizeof(R));
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &l, &r);
            R[l] = min(R[l], r);
        }
        memset(dp, -1, sizeof(dp));
        dp[0] = 0, way[0] = 1;
        for (int i = 0; i < T; ++i)
            if (dp[i] != -1) {
                int pan = T;
                for (int j = i + 1; j <= T; ++j) {
                    if (pan >= j) {
                        if (dp[j] == dp[i] + 1 || dp[j] == -1) {
                            dp[j] = dp[i] + 1;
                            way[j] += way[i];
                            way[j] %= mo;
                        } else if (dp[j] > dp[i] + 1) {
                            dp[j] = dp[i] + 1;
                            way[j] = way[i];
                        }
                    } else
                        break;
                    pan = min(pan, R[j]);
                }
            }
        printf("%lld\n%lld\n", dp[T] - 1, way[T]);
        return 0;
    }
    
    • 1

    信息

    ID
    1418
    时间
    1000ms
    内存
    512MiB
    难度
    9
    标签
    (无)
    递交数
    232
    已通过
    14
    上传者