2018冬令营模拟测试赛(三)

2018冬令营模拟测试赛(三)

[Problem A]摧毁图状树

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

这题没想到贪心 QwQ,那就没戏了……

贪心就是每次选择一个最深的且没有被覆盖的点向上覆盖 \(k\) 层,因为这个“最深的没有被覆盖的点”不可能再有其它点引出的链覆盖它了,而它又不得不被覆盖,那么向上引出的链自然越长越好。

那么接下来就是如何用数据结构快速模拟这个过程。

我们考虑处理出 \(k = 1 \sim \mathrm{max}\{dep_i\}\)(即最大深度)的所有答案,我们需要努力构造方法使得对于一个 \(k\) 我们只会访问部分节点,而不是全部。考虑到叶子节点很特殊,怎么都需要算上它们,但每次遍历一遍所有叶子又非常费时,所以我们可以一开始从“最近的叶子距离等于 \(k\)”的节点出发,以深度为关键字放在堆里,每次拿出一个节点,如果它没有被覆盖,就往上跳 \(k\) 级祖先并把它加到堆里。

我们可以用线段树 + DFS 序查询每个节点是否被覆盖(一个节点被覆盖当且仅当它子树中被拿出来过的节点的深度和它的深度之差小于 \(k\)),倍增实现跳 \(k\) 级祖先,于是所有操作都是一个 \(\mathrm{log}n\)。

考虑堆里的节点个数。下面先不考虑叶子节点,因为我们事先把它们踢出去了,事后加上叶子个数就好了。先从树上删掉所有被我们选中的节点,那么剩下的每个连通块大小不会小于 \(k-1\),再把那些点加回去,那么每个连通块大小不超过 \(k\),而每个被选中的节点顶多提供一个不会被选中的 \(k\) 级祖先。所以算法遍历到的点数不超过 \(\sum_{k=1}^{\mathrm{max}\{dep_i\}} {\frac{(n-L)}{k}}\) 显然这是调和级数,可以把它看成 \(n \mathrm{log} n\)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

#define maxn 100010
#define maxm 200010
#define maxlog 17
#define oo 2147483647

int n, m, head[maxn], nxt[maxm], to[maxm];
void AddEdge(int a, int b) {
    to[++m] = b; nxt[m] = head[a]; head[a] = m;
    swap(a, b);
    to[++m] = b; nxt[m] = head[a]; head[a] = m;
    return ;
}

int q, que[maxn], cq, task[maxn], Ans[maxn];

int nearest[maxn], dep[maxn], mxd, clo, dl[maxn], dr[maxn], uid[maxn], fa[maxn][maxlog], cntl;
vector <int> Kfar[maxn];
void build(int u) {
    uid[dl[u] = ++clo] = u;
    rep(i, 1, maxlog - 1) fa[u][i] = fa[fa[u][i-1]][i-1];
    nearest[u] = n + 1;
    mxd = max(mxd, dep[u]);
    for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u][0]) {
        fa[to[e]][0] = u;
        dep[to[e]] = dep[u] + 1;
        build(to[e]);
        nearest[u] = min(nearest[u], nearest[to[e]] + 1);
    }
    if(nearest[u] == n + 1) nearest[u] = 0, cntl++;
    dr[u] = clo;
    return ;
}
int KthParent(int u, int k) {
    rep(i, 0, maxlog - 1) if(k >> i & 1) u = fa[u][i];
    return u ? u : 1;
}

struct Seg {
    int minv[maxn<<2];
    Seg() { rep(i, 1, (maxn << 2) - 1) minv[i] = oo; }
    void modify(int o, int l, int r, int p, int tp) { // tp == 1 means add, tp == -1 means delete.
        if(l == r) {
            if(tp > 0) minv[o] = dep[uid[l]];
            else minv[o] = oo;
            return ;
        }
        int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
        if(p <= mid) modify(lc, l, mid, p, tp);
        else modify(rc, mid + 1, r, p, tp);
        minv[o] = min(minv[lc], minv[rc]);
        return ;
    }
    int query(int o, int l, int r, int ql, int qr) {
        if(ql <= l && r <= qr) return minv[o];
        int mid = l + r >> 1, lc = o << 1, rc = lc | 1, ans = oo;
        if(ql <= mid) ans = min(ans, query(lc, l, mid, ql, qr));
        if(qr > mid) ans = min(ans, query(rc, mid + 1, r, ql, qr));
        return ans;
    }
} sg;

struct cmp {
    bool operator () (const int& a, const int& b) const {
        return dep[a] < dep[b];
    }
};
priority_queue <int, vector <int>, cmp> Q;
int grasp[maxn], cntg;
void solve(int k) {
    rep(i, 0, (int)Kfar[k].size() - 1) Q.push(Kfar[k][i]);
    while(!Q.empty()) {
        int u = Q.top(); Q.pop();
        if(sg.query(1, 1, n, dl[u], dr[u]) < dep[u] + k || nearest[u] < k) continue;
        grasp[++cntg] = u;
        sg.modify(1, 1, n, dl[u], 1);
        Q.push(KthParent(u, k));
    }
    Ans[k] = cntg + cntl;
    while(cntg) sg.modify(1, 1, n, dl[grasp[cntg--]], -1);
    return ;
}

int main() {
    n = read();
    rep(i, 1, n - 1) {
        int a = read(), b = read();
        AddEdge(a, b);
    }
    build(1);
    q = read();
    rep(i, 1, q) {
        que[i] = read();
        task[i] = que[i] = que[i] <= mxd ? que[i] : mxd;
    }
    sort(task + 1, task + q + 1);
    cq = unique(task + 1, task + q + 1) - task - 1;

    rep(i, 1, n) Kfar[nearest[i]].push_back(i);
    rep(i, 1, cq) solve(task[i]);

    rep(i, 1, q) printf("%d\n", Ans[que[i]]);

    return 0;
}

[Problem B]排列统计

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

妈妈呀这题 dp 好神!思路很棒。

引用一下原题解的话“我们想进行 dp,必须设法避免指数级的状态设计。为了做到这一点,我们尝试枚举计算每个值对答案的贡献、每个位置对答案的贡献,发现怎么都避免不了指数级状态的支配。考虑换一种思路——枚举每个值在每个位置对答案产生的贡献!”

这样似乎“枚举”次数多了,也即进行 dp 的轮数多了,但是我们却可以把状态降成多项式级别的,神奇吧!

设 \(f(i, j, p, c)\) 表示进行了 \(i\) 轮交换;在目标位置前的比目标数字大的数的个数为 \(j\);目标数字在目标位置左边时 \(p = 0\),在目标位置上时 \(p = 1\),在目标位置右边时 \(p = 2\);目标位置上的数小于目标数字时 \(c = 0\),等于目标数字时 \(c = 1\),大于目标数字时 \(c = 2\);在这种情况下的方案数。转移就是枚举每种数字之间的交换(即目标位置左边比目标数字小的数、左边大数、目标位置上的数、右边小数、右边大数、目标数字,详见代码注释)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

#define maxn 110
#define MOD 1000000007
#define LL long long

int n, K, A[maxn], f[maxn][maxn][3][3], ans;

void upd(int& a, LL b) {
    a = (b + a) % MOD;
    return ;
}

int Pow(int a, int b) {
    int ans = 1, t = a;
    while(b) {
        if(b & 1) ans = (LL)ans * t % MOD;
        t = (LL)t * t % MOD; b >>= 1;
    }
    return ans;
}

int main() {
    n = read(); K = read();
    rep(i, 1, n) A[i] = read();

    rep(val, 1, n) rep(pos, 1, val) {
        int _j = 0, _p, _c;
        rep(i, 1, pos - 1) if(A[i] > val) _j++;
        rep(i, 1, n) if(A[i] == val) {
            if(i < pos) _p = 0;
            if(i == pos) _p = 1;
            if(i > pos) _p = 2;
        }
        if(A[pos] < val) _c = 0;
        if(A[pos] == val) _c = 1;
        if(A[pos] > val) _c = 2;
        memset(f, 0, sizeof(f));
        f[0][_j][_p][_c] = 1;
        // printf("start(%d, %d):\n", val, pos);
        rep(i, 0, K - 1) rep(j, 0, min(n - val, pos - 1)) rep(p, 0, 2) rep(c, 0, 2) if(f[i][j][p][c]) {
            int now = f[i][j][p][c], ls = pos - 1 - j - (p == 0), ll = j, rs = val - 1 - ls - (c == 0), rl = n - val - ll - (c == 2);
            /*printf("f[%d][%d][%d][%d] = %d | %d %d %d %d\n", i, j, p, c, f[i][j][p][c], ls, ll, rs, rl);
            if(i == K) continue; // */
            // symbol <> means "swap with".
            // left smaller <> left smaller
            if(ls) upd(f[i+1][j][p][c], (LL)now * ls * ls);
            // left smaller <> left larger
            if(ls && ll) upd(f[i+1][j][p][c], (LL)now * ls * ll * 2);
            // left smaller <> number on position
            if(ls) upd(f[i+1][j+(c==2)][p==1?0:p][0], (LL)now * ls * 2);
            // left smaller <> right smaller
            if(ls && rs) upd(f[i+1][j][p][c], (LL)now * ls * rs * 2);
            // left smaller <> right larger
            if(ls && rl) upd(f[i+1][j+1][p][c], (LL)now * ls * rl * 2);
            // left larger <> left larger
            if(ll) upd(f[i+1][j][p][c], (LL)now * ll * ll);
            // left larger <> number on position
            if(ll) upd(f[i+1][j-(c!=2)][p==1?0:p][2], (LL)now * ll * 2);
            // left larger <> right smaller
            if(ll && rs) upd(f[i+1][j-1][p][c], (LL)now * ll * rs * 2);
            // left larger <> right larger
            if(ll && rl) upd(f[i+1][j][p][c], (LL)now * ll * rl * 2);
            // number on position <> number on position
            upd(f[i+1][j][p][c], now);
            // number on position <> right smaller
            if(rs) upd(f[i+1][j][p==1?2:p][0], (LL)now * rs * 2);
            // number on position <> right larger
            if(rl) upd(f[i+1][j][p==1?2:p][2], (LL)now * rl * 2);
            // right smaller <> right smaller
            if(rs) upd(f[i+1][j][p][c], (LL)now * rs * rs);
            // right smaller <> right larger
            if(rs && rl) upd(f[i+1][j][p][c], (LL)now * rs * rl * 2);
            // right larger <> right larger
            if(rl) upd(f[i+1][j][p][c], (LL)now * rl * rl);
            if(p != 1 && c != 1) { // (ONLY when y is not on position)
                // val y <> left smaller
                if(ls) upd(f[i+1][j][0][c==1?0:c], (LL)now * ls * 2);
                // val y <> left larger
                if(ll) upd(f[i+1][j-(p!=0)][0][c==1?2:c], (LL)now * ll * 2);
                // val y <> number on position
                upd(f[i+1][j+(p==0&&c==2)][1][1], 2ll * now);
                // val y <> right smaller
                if(rs) upd(f[i+1][j][2][c==1?0:c], (LL)now * rs * 2);
                // val y <> right larger
                if(rl) upd(f[i+1][j+(p==0)][2][c==1?2:c], (LL)now * rl * 2);
                // val y <> val y
                upd(f[i+1][j][p][c], now);
            }
        }
        upd(ans, f[K][0][1][1]);
        // printf("add: %d\n", f[K][0][1][1]);
    }

    ans = (LL)ans * Pow(Pow(n, K << 1), MOD - 2) % MOD;
    printf("%d\n", ans);

    return 0;
}

[Problem C]归并排序

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

首先这题需要观察出一些性质:我们把归并排序最后可能排错的两个数看成一对数,对于一对数 \((a, b)\),不妨令 \(a < b\),因为大小关系是等概率出现的;那么当这对数经过归并排序之后的顺序是先 \(a\) 后 \(b\),它们就有可能离得很远,但一定会保证 \(b\) 每时每刻都在 \(a\) 的右边;如果顺序是先 \(b\) 后 \(a\),我们会发现,在每次归并的时候,如果 \(b\) 能进入序列(这时一定是另一半轮到了一个大于 \(b\) 的数 \(c\)),那么紧随其后的 \(a\) 更能进入序列,因为 \(a < b < c\)。

令 \(a_i(i \in [1, n])\) 表示排序前的排列。

接下来对于每个询问,假设询问的是位置 \(x\) 到位置 \(y\),我们看两个数都比 \(a_x\) 小的数对(也即最大值比 \(a_x\) 小的数对),和两个数都比 \(a_x\) 大的数对(也即最小值比 \(a_x\) 大的数对),剩下的就是两个数“跨过”\(a_x\) 的数对。不难发现都比 \(a_x\) 小的数对肯定整对都在 \(a_x\) 的前面,都比 \(a_x\) 大的数对肯定都在 \(a_x\) 的后面,“跨过”\(a_x\) 的数对有 \(\frac{1}{2}\) 的概率有一个数在 \(a_x\) 前面,\(\frac{1}{2}\) 的概率都在 \(a_x\) 的后面,这样的话,组合数算一下方案数再除以 \(2\) 的幂就好了。

注意 \(a_x\) 所在对交换可能会导致情况不一样,记得讨论。

统计那个东西开两个树状数组分别维护数对中较小值和较大值就好了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

#define maxn 70000
#define MOD 1000000007
#define LL long long
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)

int n, bel[maxn], Arr[maxn];
pii A[maxn];

struct BitArray {
    int C[maxn];
    void upd(int x, int v) {
        for(; x <= n; x += x & -x) C[x] += v;
        return ;
    }
    int sum(int x) {
        int ans = 0;
        for(; x; x -= x & -x) ans += C[x];
        return ans;
    }
} mx, mn;

int Pow(int a, int b) {
    int ans = 1, t = a;
    while(b) {
        if(b & 1) ans = (LL)ans * t % MOD;
        t = (LL)t * t % MOD; b >>= 1;
    }
    return ans;
}

int fac[maxn], ifac[maxn];
int calc(int n, int m) { return (LL)fac[n] * ifac[m] % MOD * ifac[n-m] % MOD; }

int main() {
    n = read();
    for(int i = 1; i <= n; i += 2) {
        bel[i] = bel[i+1] = (i - 1 >> 1) + 1;
        // printf("%d %d  %d %d\n", i, i + 1, bel[i], bel[i+1]);
        int x = read(), y = read();
        Arr[i] = x; Arr[i+1] = y;
        if(x > y) swap(x, y);
        A[bel[i]] = mp(x, y);
        mx.upd(y, 1); mn.upd(x, 1);
    }

    fac[0] = ifac[0] = 1;
    rep(i, 1, n) fac[i] = (LL)fac[i-1] * i % MOD, ifac[i] = (LL)ifac[i-1] * Pow(i, MOD - 2) % MOD;
    int q = read();
    while(q--) {
        int tp = read(), x = read(), y = read();
        if(tp == 1) {
            swap(Arr[x], Arr[y]);
            if(bel[x] == bel[y]) continue;
            mx.upd(A[bel[x]].y, -1); mn.upd(A[bel[x]].x, -1);
            mx.upd(A[bel[y]].y, -1); mn.upd(A[bel[y]].x, -1);
            A[bel[x]] = mp(min(Arr[(bel[x]<<1)-1], Arr[bel[x]<<1]), max(Arr[(bel[x]<<1)-1], Arr[bel[x]<<1]));
            A[bel[y]] = mp(min(Arr[(bel[y]<<1)-1], Arr[bel[y]<<1]), max(Arr[(bel[y]<<1)-1], Arr[bel[y]<<1]));
            // printf("%d %d %d | %d %d %d\n", bel[x], A[bel[x]].x, A[bel[x]].y, bel[y], A[bel[y]].x, A[bel[y]].y);
            mx.upd(A[bel[x]].y, 1); mn.upd(A[bel[x]].x, 1);
            mx.upd(A[bel[y]].y, 1); mn.upd(A[bel[y]].x, 1);
        }
        if(tp == 2) {
            int alls, allb, rest, ans = 0;
            if(Arr[x] == A[bel[x]].y) {
                alls = mx.sum(Arr[x] - 1); allb = mn.sum(n) - mn.sum(Arr[x]); rest = (n >> 1) - alls - allb;
                if((alls << 1) > y - 1 || (alls << 1) + rest < y - 1) puts("0");
                else printf("%lld\n", (LL)calc(rest, y - 1 - (alls << 1)) * Pow(Pow(2, rest), MOD - 2) % MOD);
                continue;
            }
            alls = mx.sum(A[bel[x]].x - 1); allb = mn.sum(n) - mn.sum(A[bel[x]].x); rest = (n >> 1) - alls - allb - 1;
            if((alls << 1) > y - 1 || (alls << 1) + rest < y - 1) ;
            else ans += (LL)calc(rest, y - 1 - (alls << 1)) * Pow(Pow(2, rest + 1), MOD - 2) % MOD;
            alls = mx.sum(A[bel[x]].y - 1); allb = mn.sum(n) - mn.sum(A[bel[x]].y); rest = (n >> 1) - alls - allb - 1;
            if((alls << 1) > y - 2 || (alls << 1) + rest < y - 2) ;
            else (ans += (LL)calc(rest, y - 2 - (alls << 1)) * Pow(Pow(2, rest + 1), MOD - 2) % MOD) %= MOD;
            printf("%d\n", ans);
        }
    }

    return 0;
}
时间: 2024-10-11 01:09:50

2018冬令营模拟测试赛(三)的相关文章

2018冬令营模拟测试赛(十七)

2018冬令营模拟测试赛(十七) [Problem A]Tree 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 这个数据范围肯定是树上背包了. 令 \(f(i, j, k)\) 表示子树 \(i\) 中选择了 \(j\) 个节点,路径与根的连接情况为 \(k\),具体地: \(k = 0\) 时,路径的两个端点

2018冬令营模拟测试赛(五)

2018冬令营模拟测试赛(五) [Problem A][UOJ#154]列队 试题描述 picks 博士通过实验成功地得到了排列 \(A\),并根据这个回到了正确的过去.他在金星凌日之前顺利地与丘比签订了契约,成为了一名马猴烧酒. picks 博士可以使用魔法召唤很多很多的猴子与他一起战斗,但是当猴子的数目 \(n\) 太大的时候,训练猴子就变成了一个繁重的任务. 历经千辛万苦,猴子们终于学会了按照顺序排成一排.为了进一步训练,picks 博士打算设定一系列的指令,每一条指令 \(i\) 的效果

2018冬令营模拟测试赛(十九)

2018冬令营模拟测试赛(十九) [Problem A]小Y 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 目前未知. 这题目前就能做到 \(O(n \sqrt{M} \log n)\),其中 \(M\) 是逆序对数,然而会被卡 \(T\):当然这题暴力可以拿到和左边那个算法一样的分数,只要暴力加一个剪枝:当左

2018.8.6 Noip2018模拟测试赛(十九)

日期: 八月六号  总分: 300分  难度: 提高 ~ 省选    得分: 10分(MMP) 题目目录: T1:Tree T2:异或运算 T3:Tree Restoring 赛后反思: Emmmmmmm…… 一直在打第一题…… 结果考完才发现dp少了一种情况…… 除此之外,我无话可说…… Emmmmmm…… 题解: T1:Tree 树形背包dp,设$f[i][j][k(0/1/2)]$为$i$的子树中,选$j$条边,0:从$i$出发,到$i$结束/1:从$i$出发,到$i$的某个后代结束/2:

[CSP-S模拟测试]:赛(贪心+三分)

题目描述 由于出题人思维枯竭所以想不出好玩的背景.有$n$个物品,第$i$个物品的价格是$v_i$,有两个人,每个人都喜欢$n$个物品中的一些物品.要求选出正好$m$个物品,满足选出的物品中至少有$k$个物品被第一个人喜欢,$k$个物品被第二个人喜欢.并求出最小的价格和. 输入格式 第一行三个数$n,m,k$.第二行$n$个数,第$i$个数表示$v_i$.第三行包含一个数$a$,表示第一个人喜欢的物品数.第四行包含$a$个数,表示第一个人喜欢的物品是哪几个.第五行包含一个数$b$,表示第二个人喜

[北京集训测试赛(三)]灯(Light)-奇怪乱搞数学题-素数

Problem 灯 题目大意 n盏灯排成一列,标号一到n,一开始标号为1的灯亮着. 现在依次对于2~n的每一个质数pi,指定一盏亮着的灯ai,点亮所有标号为$A[i]\pm kP_i$的灯. 有spj,任意一种方案即可. 输入一个整数n,输出点灯方案. Solution 首先写个暴力,考虑一下小范围的数据. 我们发现$n<16$的时候没有完美解,都是n-1.再算下去,发现$n>16$的时候任意一组都有完美解. 我们分析一下这个玩意儿. 把一到n的灯集体下标前移1,变成0~n-1.这时候当我们点

【20180318】2018北京集训测试赛(六)

菜鸡滚回石家庄了233 Problem B: 求和 题解&反思: 好久没写反演了真刺激 大力推公式就好咯 \[ \sum_{i=1}^{n}\sum_{j=1}^{i}\sum_{k=1}^{i}gcd(i,j,k) \] \[ =\sum_{i=1}^{n}\sum_{d|i}d\sum_{j=1}^{i}\sum_{k=1}^{i}[gcd(i,j,k)==d] \] \[ =\sum_{i=1}^{n}\sum_{d|i}d\sum_{j=1}^{\left \lfloor \frac{i

2018 蓝桥杯省赛 B 组模拟赛(一)

2018 蓝桥杯省赛 B 组模拟赛(一) A.今天蒜头君带着花椰妹和朋友们一起聚会,当朋友们问起年龄的时候,蒜头君打了一个哑谜(毕竟年龄是女孩子的隐私)说:“我的年龄是花椰妹年龄个位数和十位数之和的二倍”. 花椰妹看大家一脸懵逼,就知道大家也不知道蒜头君的年龄,便连忙补充道:“我的年龄是蒜头君个位数和十位数之和的三倍”. 请你计算:蒜头君和花椰妹年龄一共有多少种可能情况? 提醒:两位的年龄都是在 [10,100)[10,100) 这个区间内. 题解: 暴力枚举 answer: 1 代码如下: #

2018.10.2浪在ACM 集训队第二次测试赛

2018.10.26 浪在ACM 集训队第二次测试赛 题目一览表(Green color indicate understand and Accept) 来源 考察知识点 完成时间 A 1273 海港(比赛过题) NOIP 普及组 2016 查分数组+二分 2018.10.26 D 1272 回问日期(比赛过题) NOIP 普及组 2016 思维? 2018.10.26 G 1268 扫雷游戏(比赛过题) NOIP 普及组 2015 暴力 or DFS 2018.10.26