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

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

[Problem A]小Y

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

目前未知。

这题目前就能做到 \(O(n \sqrt{M} \log n)\),其中 \(M\) 是逆序对数,然而会被卡 \(T\);当然这题暴力可以拿到和左边那个算法一样的分数,只要暴力加一个剪枝:当左区间最大值小于右区间最小值时就直接输出阶乘。

// 略(不要打我 TAT)

[Problem B]暗牧

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

这题要用到的节点不多,自然想到构建虚树。把所有边和询问所提到的点都作为关键点,每棵树分别处理,这样能把点数压成 \(4(m+q)\),边数也是这个级别的,最后跑 \(q\) 遍最短路就好了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
#include <cassert>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; 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 maxtrn 300010
#define maxlog 19
#define maxom 100010
#define maxn 400050
#define maxm 1000090
#define ool (1ll << 60)
#define LL long long
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)
 
int ToT;
struct Graph {
    int m, head[maxn], nxt[maxm], to[maxm], dist[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 ;
    }
     
    void AddEdge(int a, int b, int c) {
        assert(a >= 0 && b >= 0);
        // printf("edge %d %d, %d\n", a, b, c);
        to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
        swap(a, b);
        to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
        return ;
    }
} tr, G;
 
int fa[maxtrn][maxlog], dep[maxtrn], dfn[maxtrn], clo;
void build(int u) {
    dfn[u] = ++clo;
    rep(i, 1, maxlog - 1) fa[u][i] = fa[fa[u][i-1]][i-1];
    for(int e = tr.head[u]; e; e = tr.nxt[e]) if(tr.to[e] != fa[u][0]) {
        fa[tr.to[e]][0] = u;
        dep[tr.to[e]] = dep[u] + 1;
        build(tr.to[e]);
    }
    return ;
}
int lca(int a, int b) {
    if(dep[a] < dep[b]) swap(a, b);
    dwn(i, maxlog - 1, 0) if(dep[a] - dep[b] >= (1 << i)) a = fa[a][i];
    dwn(i, maxlog - 1, 0) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    return a == b ? a : fa[b][0];
}
 
struct Edge {
    int p1, u1, p2, u2;
    Edge() {}
    Edge(int _1, int _2, int _3, int _4): p1(_1), u1(_2), p2(_3), u2(_4) {}
} es[maxom], qs[15];
int num[(maxom<<1)+20], cntn, gnode[maxtrn<<1];
vector <int> vnode[(maxom<<1)+20];
const bool cmp(const int& a, const int& b) {
    return dfn[a] < dfn[b];
}
const bool cmpequ(const int& a, const int& b) {
    return dfn[a] == dfn[b];
}
 
const int HMOD = 1000037;
struct Hash {
    int tot, head[HMOD], nxt[maxn], id[maxn];
    pii key[maxn];
    void Insert(pii a, int v) {
        // printf("insert: pair(%d, %d) %d\n", a.x, a.y, v);
        int u = (a.x * 233 + a.y) % HMOD;
        nxt[++tot] = head[u]; id[tot] = v; key[tot] = a; head[u] = tot;
        return ;
    }
    int Find(pii a) {
        int u = (a.x * 233 + a.y) % HMOD;
        for(int e = head[u]; e; e = nxt[e]) if(key[e].x == a.x && key[e].y == a.y) return id[e];
        return -1;
    }
} hh;
 
struct Node {
    int u; LL d;
    Node() {}
    Node(int _, LL __): u(_), d(__) {}
    bool operator < (const Node& t) const { return d > t.d; }
};
LL d[maxn];
bool vis[maxn];
priority_queue <Node> Q;
LL ShortPath(int s, int t) {
    rep(i, 1, ToT) d[i] = ool;
    memset(vis, 0, sizeof(vis));
    d[s] = 0;
    Q.push(Node(s, 0));
    while(!Q.empty()) {
        int u = Q.top().u; Q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int e = G.head[u]; e; e = G.nxt[e]) if(d[G.to[e]] > d[u] + G.dist[e]) {
            d[G.to[e]] = d[u] + G.dist[e];
            if(!vis[G.to[e]]) Q.push(Node(G.to[e], d[G.to[e]]));
        }
    }
    return d[t];
}
 
int main() {
    int n = read(), m = read(), q = read();
    rep(i, 1, n - 1) {
        int a = read(), b = read();
        tr.AddEdge(a, b);
    }
    build(1);
    rep(i, 1, m) {
        int p1 = read(), u1 = read(), p2 = read(), u2 = read();
        es[i] = Edge(p1, u1, p2, u2);
        num[++cntn] = u1; num[++cntn] = u2;
    }
    rep(i, 1, q) {
        int p1 = read(), u1 = read(), p2 = read(), u2 = read();
        qs[i] = Edge(p1, u1, p2, u2);
        num[++cntn] = u1; num[++cntn] = u2;
    }
    sort(num + 1, num + cntn + 1);
    cntn = unique(num + 1, num + cntn + 1) - num - 1;
     
    rep(i, 1, m) {
        es[i].u1 = lower_bound(num + 1, num + cntn + 1, es[i].u1) - num;
        es[i].u2 = lower_bound(num + 1, num + cntn + 1, es[i].u2) - num;
        // printf("%d <- %d; %d <- %d\n", es[i].u1, es[i].p1, es[i].u2, es[i].p2);
        vnode[es[i].u1].push_back(es[i].p1);
        vnode[es[i].u2].push_back(es[i].p2);
    }
    rep(i, 1, q) {
        qs[i].u1 = lower_bound(num + 1, num + cntn + 1, qs[i].u1) - num;
        qs[i].u2 = lower_bound(num + 1, num + cntn + 1, qs[i].u2) - num;
        // printf("%d <- %d; %d <- %d\n", qs[i].u1, qs[i].p1, qs[i].u2, qs[i].p2);
        vnode[qs[i].u1].push_back(qs[i].p1);
        vnode[qs[i].u2].push_back(qs[i].p2);
    }
    rep(i, 1, cntn) {
        sort(vnode[i].begin(), vnode[i].end(), cmp);
        vector <int> :: iterator it = unique(vnode[i].begin(), vnode[i].end(), cmpequ);
        vnode[i].erase(it, vnode[i].end());
         
        // printf("tree %d:", i); for(auto j : vnode[i]) printf(" %d", j); putchar(‘\n‘);
         
        int cntg = 0;
        rep(j, 0, vnode[i].size() - 1) {
            gnode[++cntg] = vnode[i][j];
            if(j < vnode[i].size() - 1) gnode[++cntg] = lca(vnode[i][j], vnode[i][j+1]);
        }
        sort(gnode + 1, gnode + cntg + 1, cmp);
        cntg = unique(gnode + 1, gnode + cntg + 1, cmpequ) - gnode - 1;
        rep(j, 1, cntg) hh.Insert(mp(i, gnode[j]), ++ToT);
        rep(j, 1, cntg)
            if(j > 1) {
                int a = lca(gnode[j-1], gnode[j]);
                G.AddEdge(hh.Find(mp(i, a)), hh.Find(mp(i, gnode[j])), dep[gnode[j]] - dep[a]);
            }
    }
    rep(i, 1, m) G.AddEdge(hh.Find(mp(es[i].u1, es[i].p1)), hh.Find(mp(es[i].u2, es[i].p2)), 1);
     
    rep(i, 1, q) {
        int p1 = qs[i].p1, u1 = qs[i].u1, p2 = qs[i].p2, u2 = qs[i].u2;
        LL ans = ShortPath(hh.Find(mp(u1, p1)), hh.Find(mp(u2, p2)));
        if(ans < ool) printf("%lld\n", ans); else puts("impossible");
    }
     
    return 0;
}

[Problem C]大根

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

这题可以转化成生成 \(k\) 个不相交区间,要求每个元区间都包含至少一个生成的区间,且生成的区间至少被一个原区间包含。

于是变成两种贪心取最优:

  • 将包含别的区间的区间放到集合 \(B\) 中,否则放到集合 \(A\) 中,然后枚举 \(A\) 中分 \(k_1\) 类,那么 \(B\) 中选择 \(k - k_1\) 个。\(B\) 中选的一定是单个区间。这样能保证合法(想想为什么)。
  • 按长度排序取前 \(k-1\) 个,然后剩下的所有分一类。(这就是在上面有区间集合的交集为 \(0\) 的时候这种贪心才会起作用)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; 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 1000010
#define LL long long
 
struct Line {
    int l, r;
    Line() {}
    Line(int _, int __): l(_), r(__) {}
    bool operator == (const Line& t) const { return l == t.l && r == t.r; }
    bool operator < (const Line& t) const { return r != t.r ? r < t.r : l > t.l; }
    Line operator * (const Line& t) const { return Line(max(l, t.l), min(r, t.r)); }
    Line operator *= (const Line& t) { *this = *this * t; return *this; }
} ls[maxn], getl[maxn], bigl[maxn];
int n, K, cntg, cntb, val[maxn];
 
bool cmplen(Line a, Line b) { return a.r - a.l > b.r - b.l; }
 
int main() {
    n = read(); K = read();
    rep(i, 1, n) {
        int l = read(), r = read();
        ls[i] = Line(l, r);
    }
     
    sort(ls + 1, ls + n + 1);
    for(int i = 1; i <= n; ) {
        getl[++cntg] = ls[i++];
        while(i <= n && ls[i] * ls[i-1] == ls[i-1]) bigl[++cntb] = ls[i++];
    }
    sort(bigl + 1, bigl + cntb + 1, cmplen);
    sort(getl + 1, getl + cntg + 1);
    LL sum = 0, ans = 0;
    rep(i, 1, cntg) sum += getl[i].r - getl[i].l;
    rep(i, 1, cntg - 1) val[i] = getl[i+1].r - getl[i].l;
    sort(val + 1, val + cntg), reverse(val + 1, val + cntg);
    dwn(i, cntg - 1, K) sum -= val[i];
    rep(i, cntg + 1, K) sum += bigl[i-cntg].r - bigl[i-cntg].l;
    int cg, cb;
    if(cntg <= K) cg = cntg, cb = K - cntg;
    else cg = K, cb = 0;
    ans = max(ans, sum);
    for(; cg > 1;) {
        sum -= val[--cg];
        cb++; sum += bigl[cb].r - bigl[cb].l;
        ans = max(ans, sum);
    }
     
    sum = 0;
    sort(ls + 1, ls + n + 1, cmplen);
    rep(i, 1, K - 1) sum += ls[i].r - ls[i].l;
     
    printf("%lld\n", max(ans, sum));
     
    return 0;
}

原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8323454.html

时间: 2024-07-29 22:48:38

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

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

2018冬令营模拟测试赛(三) [Problem A]摧毁图状树 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 这题没想到贪心 QwQ,那就没戏了-- 贪心就是每次选择一个最深的且没有被覆盖的点向上覆盖 \(k\) 层,因为这个"最深的没有被覆盖的点"不可能再有其它点引出的链覆盖它了,而它又

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

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

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

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

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:

【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

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

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

29、蛤蟆的数据结构笔记之二十九数组之硬币抛掷模拟

29.蛤蟆的数据结构笔记之二十九数组之硬币抛掷模拟 本篇名言:"人生是各种不同的变故.循环不已的痛苦和欢乐组成的.那种永远不变的蓝天只存在于心灵中间,向现实的人生去要求未免是奢望.-- 巴尔扎克" 欢迎转载,转载请标明出处: 1.  硬币抛掷 如果抛掷硬币N次,看到头像的期望值是N/2次,但实际值也可能是0~N次,在程序中进行M次试验,M和N都在代码中定义.它使用一个数组f来跟踪出现"i次头像"的概率,其中0≤j≤N.然后打印试验结果的柱状图,每出现10次用1个星号

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

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

菜鸟学Java(十九)——WEB项目测试好帮手,Maven+Jetty

做WEB开发,测试是一件很费时间的事情.所以我们就应该用更简单.更快捷的方式进行测试.今天就向大家介绍一个轻量级的容器--jetty.j今天说的etty是Maven的一个插件jetty-maven-plugin,与Maven配合起来使用非常的方便,它的配置也非常的简单,下面我们就看看它怎么用吧! 在pom.xml 文件的<project>标签下加入如下代码: <build> <plugins> <plugin> <groupId>org.mort