• 4 November in ss


    Contest

    A. 输油管道问题

    某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有 (n) 口油井的油田。从每口油井都要有一条输油管道沿最短路经 (或南或北) 与主管道相连。如果给定 (n) 口油井的位置, 即它们的 (x) 坐标(东西向)和 (y) 坐标(南北向), 应如何确定主管道的最优位置, 即使各油井到主管道之间的输油管道长度总和最小的位置? 证明可在线性时间内确定主管道的最优位置。 (1le nle 10000)

    观察到 (x) 坐标与答案无关,题目转变为求 (sum |Y-y_i|) 的最大值。

    贪心。易证,中位数即为 (Y) 的值。

    当然我在考场上是用玄学二分做出来的。)

    B. ssoj3147 跑步(run)

    小 A 要参加一次 1000 米跑步比赛。 一开始他的速度为 1 m/s,在跑步过程中他会越跑越累,所以会进行若干次减速。第一次减速后,速度变为 (frac{1}{2}) m/s;第二次减速后,速度变为 (frac{1}{3}) m/s,依次类推。你现在知道小 A 会在什么时间或者是哪里进行减速,有 (n) 个这样的事件:T x 表示小 A 会在比赛开始后 (x) 秒进行一次减速。D x 表示小 A 会在恰好跑了 (x) 米之后进行一次减速。现在给你这些事件。你要帮小 A 算出他用这种方式到达终点所需要的时间是多少秒。可能存在两个事件恰好同时发生,那么在这一时刻速度就会减小两次。

    模拟即可。注意时间、位移、速度的先后顺序,以及哨兵变量自增的时机。考场上就是这点折腾了我好久。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    int n, t[10003], d[10003], vn=1;
    double lt, ld, v=1;
     
    int main() {
        scanf("%d", &n);
        for (int k=1; k<=n; ++k) {
            int a=0;
            char c=getchar(); while (c!='T' && c!='D') c=getchar(); scanf("%d", &a);
            if (c=='T') t[++t[0]]=a; else d[++d[0]]=a;
        }
        sort(t+1, t+t[0]+1); sort(d+1, d+d[0]+1);
        for (int i=1, j=1; i<=t[0] && j<=d[0]; ) {
            double dt=(t[i]-lt)*v + ld;
            if (dt<d[j]) lt=t[i++], ld=dt, v=1.0/(++vn);
            else if (dt>d[j]) lt+=(d[j]-ld)/v, ld=d[j++], v=1.0/(++vn);
            else lt=t[i++], ld=dt, ++j, vn+=2, v=1.0/vn;
            if (i>t[0]) { 
                for (; j<=d[0]; ++j) lt+=(d[j]-ld)/v, ld=d[j], v=1.0/(++vn);
                break;
            }
            if (j>d[0]) {
                for (; i<=t[0]; ++i) ld+=(t[i]-lt)*v, lt=t[i], v=1.0/(++vn);
                break;
            }
        }
        if (ld<1000.0) lt+=(1000.0-ld)/v;
        printf("%.0lf
    ", lt);
        return 0;
    }
    

    C. ssoj2977 流图(flow)

    如果一张有向图存在一个点可以到达所有的点,则称这个图是一个流图 (Flow Graph)。现在给定一张有向图,请判断这张图是不是流图;如果是,输出所有的点 (r) 满足点 (r) 可以到达图中的所有点。(1le n,mle 1000)

    DFS?!! 注意到不重复 DFS 全图的时间复杂度是 (O(m)),所以可以采用 (O(nm)) 的极端暴力做法,即以每个点为起点跑 DFS。太暴力了考场上没想出来……

    #include <cstdio>
    #include <cstring>
     
    int n, m, ant, ans[1005];
    int head[1005], nex[1005], to[1005];
    int v[1005], cnt;
     
    inline void add(int x, int y) {
        nex[++head[0]]=head[x], head[x]=head[0], to[head[0]]=y;
    }
    void dfs(int x) {
        for (int i=head[x]; i; i=nex[i]) if (!v[to[i]])
            ++cnt, v[to[i]]=1, dfs(to[i]);
    }
     
    int main() {
        scanf("%d%d", &n, &m);
        for (int i=1, a, b; i<=m; ++i)
            scanf("%d%d", &a, &b), add(a, b);
        for (int i=1; i<=n; ++i) {
            memset(v, 0, sizeof v); cnt=1, v[i]=1;
            dfs(i); if (cnt==n) ans[++ant]=i;
        }
        if (!ant) {putchar('0'); return 0; }
        printf("%d
    ", ant);
        for (int i=1; i<=ant; ++i) printf("%d ", ans[i]);
        return 0;
    }
    

    D. ssoj3146 物品选取

    (n) 件物品,每件物品尺寸为 (A_i),价值为 (B_i)。令 (A_max) 为所选物品中最大的尺寸,(A_min) 为所选物品中最小的尺寸。令 (sum) 为选择物品的价值之和。选择一些物品,使得 (sum−(A_max−A_min)) 最大。(2le nle 5 imes 10^5, 1le A_ile 10^{15}, 1le B_ile 10^9)

    容易想到按照 (A) 排序,枚举最值。(sum) 预处理前缀和。可得 (O(n^2)) 做法。显然不是正解。

    考虑用算式表示答案:令 (i) 为最大值,(j) 为最小值,最大化 (sum(i)-sum(j-1)-A_i+A_j=sum(i)-A_i+A_j-sum(j-1))。当前状态答案只与 (i,j) 有关。

    尺取法。枚举 (i),对于每个 (i),维护 (A_j-sum(j-1)) 的最大值。时间复杂度降为 (O(n))

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define ll long long
     
    int n; ll sum[500003], ans;
    struct node {
        ll A, B;
        bool operator < (const node& a) const {return A<a.A; }
    } p[500003];
     
    int main() {
        scanf("%d", &n);
        for (int i=1; i<=n; ++i) scanf("%lld%lld", &p[i].A, &p[i].B);
        sort(p+1, p+n+1);
        for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+p[i].B;
        ll m=0, t=0;
        for (int i=1; i<=n; ++i) {
            m=sum[i]-p[i].A;
            t=max(t, p[i].A-sum[i-1]);
            ans=max(ans, m+t);
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    小结

    都是简单的做法,但是因为时间复杂度估计失误,不敢于写出来。看来暴力、贪心写得不够多……是啊,既然都是 NOIP 范围内的知识,那怎么区分高手?还是依靠思维难度取胜!

  • 相关阅读:
    jquery判断浏览器类型
    webservice soapheader验证方法
    webservice跨域文件,好多年前的东西,远程调用,js服务器端使用,可以远程调用
    c# 动态调用webservice 转录一下
    linq使用 count与sum等
    js date扩展方法
    c#深拷贝的一个方法
    javascript jquery document.ready window.onload
    带你上手一款下载超 10 万次的 IDEA 插件
    Knative Serving 健康检查机制分析
  • 原文地址:https://www.cnblogs.com/greyqz/p/9915190.html
Copyright © 2020-2023  润新知