zoukankan      html  css  js  c++  java
  • 2020.10.07提高组模拟

    2020.10.07【NOIP提高A组】模拟


    6817. 【2020.10.07提高组模拟】DNA 序列


    Description

    给定一个长为 (n (n leq 5 imes 10^6)) 的只由 (A, G, C, T) 组成的字符串,求由连续 (k (k leq 10)) 个字符组成子串的最多出现次数。

    Solution

    可以将字符当成四进制数,最大不会超过 (1048576 (4^{10})),时间复杂度 (O(nk))

    6818. 【2020.10.07提高组模拟】数列递推


    Description

    每组数据(数据组数 (leq 2.5 imes 10^5))给定 (a_0, a_1),递推式 (a_{i + 2} = ka_{i + 1} + a_i, i in N, k in N^+)
    再给定集合 (S subset N),求最小的 (S_i) 使得 (a_{S_i}) 最大,及最小的 (S_j) 使得 (a_{S_j}) 最小。

    Solution

    首先可以发现,当第一次出现 (a_i imes a_{i + 1} > 0) 时(即 (a_i)(a_{i + 1}) 同号),(a_j (j geq i)) 是单调上升/下降的。
    而且出现的位置比较靠前。

    证明:
    (b_i = |a_i|)
    显然,在 a 变得单调之前,都是正负交替出现的,所以 (b_{i + 2} = -kb_{i + 1} + b_i),
    变换得 (b_{i + 2} + kb_{i + 1} = b_i)
    (b_i geq 0)(b_i geq b_{i + 2}),所以 (b_i geq (k + 1)b_{i + 1}),即 (b_{i + 1} leq frac{b_i}{k + 1})
    那么最大也就是 (log_2 (|a_1|)) 级别的。

    所以就可以暴力算出单调以前的数,对于单调后只需要计算到单调前最大/最小的 a 的级别就行,也不会太多。
    当然,单调后要分正负情况讨论。

    6819. 【2020.10.07提高组模拟】七曜圣贤 (sage)


    Solution

    首先对于被扔出去的红茶,可以用一个队列维护,然后可以发现:

    对于队列中两个元素 (q_i, q_j (i < j)),如果 (q_i > q_j),那么将 (q_i) 捡回去后对答案不会有影响

    所以可以用一个单调队列维护对答案有影响的红茶,对答案还有影响的就是通过操作一新买的红茶,这个应该很好维护。

    (实测 bitset 暴力模拟能过,而且貌似还是OJ上跑得最快的....._Find_first真是好东西2333)

    6820. 【2020.10.07提高组模拟】旅游路线 (trip)


    Solution

    首先 (c_i = min(c_i, C)),注意到题目中 (q_i leq n^2),所以花费最大为10000。
    考虑dp。
    (f_{i, j}) 表示在 i 点加一次油,还剩 j 元钱最长能走的距离,转移比较简单

    (f_{i, j} = max(f_{k, j - p_i} + d_{i, k, c_i}))

    其中 (d_{i, j, c}) 表示从 i 到 j,经过不超过 c 条边能走的最长距离,枚举一条边 ((i, k)),转移为

    (d_{i, j, c} = max(d_{k, j, c - 1} + l_{i, k}))

    求出 f 后可以用二分就算出答案,总时间复杂度为 (O(n^4 + nmC + Tlog_2n^2)),期望不得满分。

    发现时间的瓶颈在预处理 d 的时候,而 d 每次转移时第三位都只是减一,所以可以用倍增floyd做。
    (g_{i, j, l}) 表示从 i 到 j,经过不超过 (2^l) 条边能走的最长距离,转移也很简单

    (g_{i, j, l} = max(g_{i, k, l - 1} + g_{k, j, l - 1}))

    比较难的在于怎么用 g 预处理出 d,可以发现转移 f 的时候 (d_i) 的第三维都是 (c_i),反正都要走 (c_i) 步,所以可以压掉第三维。
    那么只需要将 (c_i) 拆分二进制位,用 (tmp_{i, j}) 暂存,

    (tmp_{i, j} = max(d_{i, k} + g_{k, j, l}))     ((2^l) & (c_i))
    (d_{i, j} = tmp_{i, j})

    这样子时间复杂度就是 (O(n^4 + n^3log_2C + T log_2N^2)) 的了

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define N 100
    #define M 10000
    #define L 17
    
    #define fo(i, x, y) for(int i = x; i <= y; i ++)
    #define Mes(a, x) memset(a, x, sizeof a)
    
    void read(int &x) {
        char ch = getchar(); x = 0;
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
    }
    
    int f[N + 1][10001], g[N + 1][N + 1][L + 1], d[N + 1][N + 1], tmp[N + 1][N + 1], p[N + 1], c[N + 1];
    
    int n, m, C, T;
    
    const int inf = 0x3f3f3f3f;
    
    int Max(int x, int y) { return x > y ? x : y; }
    
    int Min(int x, int y) { return x < y ? x : y; }
    
    int main() {
        freopen("trip.in", "r", stdin);
        freopen("trip.out", "w", stdout);
    
        read(n), read(m), read(C), read(T);
        fo(i, 1, n) read(p[i]), read(c[i]);
        Mes(g, 0xc2);
        for (int i = 1, u, v, l; i <= m; i ++) {
            read(u), read(v), read(l);
            g[u][v][0] = Max(g[u][v][0], l);
        }
        fo(i, 1, n) g[i][i][0] = 0;
    
        fo(i, 1, n) c[i] = Min(c[i], C);
    
        fo(l, 1, L) fo(i, 1, n) fo(j, 1, n) fo(k, 1, n)
            g[i][j][l] = Max(g[i][j][l], g[i][k][l - 1] + g[k][j][l - 1]);
    
        fo(i, 1, n) {
            fo(j, 1, n) d[i][j] = tmp[i][j] = -inf;
            d[i][i] = 0;
            fo(l, 0, L) if (c[i] & (1 << l)) {
                fo(j, 1, n) fo(k, 1, n)
                    tmp[i][j] = Max(tmp[i][j], d[i][k] + g[k][j][l]);
                fo(j, 1, n) d[i][j] = tmp[i][j];
            }
        }
    
        fo(i, 1, n) f[i][0] = 0;
        fo(j, 1, 10000) fo(i, 1, n) if (j >= p[i]) fo(k, 1, n)
            f[i][j] = Max(f[i][j], f[k][j - p[i]] + d[i][k]);
    
        int x, y, z, l, r, mid, s;
        fo(i, 1, T) {
            read(x), read(y), read(z);
            l = 1, r = y, mid = 0, s = y + 1;
            while (l <= r) {
                mid = l + r >> 1;
                f[x][mid] >= z ? r = (s = mid) - 1 : l = mid + 1;
            }
    
            printf("%d
    ", y - s);
        }
    
        return 0;
    }
    
  • 相关阅读:
    jupyter notebook 远程连接访问服务器
    spark py4j.protocol.Py4JNetworkError: An error occurred while trying to conn
    cudart64_101.dll not found解决方法
    windows tensorflow无法下载Fashion-mnist的解决办法
    dataframe apply函数多个结果拆分给多列
    tensorflow安装
    pandas DataFrame中agg聚合后重命名列标题
    操作系统-第五章-进程调度
    操作系统-第四章-多线程编程
    操作系统-第三章-进程
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/13777819.html
Copyright © 2011-2022 走看看