2020.10.07提高组模拟

2020.10.07【NOIP提高A组】模拟


 

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


Description

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

Solution

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

 

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


Description

每组数据(数据组数 \(\leq 2.5 \times 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 \times 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\n", y - s);
    }

    return 0;
}
posted @ 2020-10-07 16:31  buzzhou  阅读(178)  评论(0)    收藏  举报