zoukankan      html  css  js  c++  java
  • HGOI20191115 模拟赛 题解

    Problem A 表演

    有$n$个有点权的点,$m$个有边权的边。对于每个点$u$,输出从这个点出发到$v$,其路径权值的两倍加上v的点权和最小的值。

    对于$100\%$的数据,满足$1 leq n,m leq 2 imes 10^5 $

    Solution : 

      考虑一个简单的转移,$f[u]$表示点$u$的最小答案,最初$f[u]$ 为$u$的点权。

      每一次更新,就是相邻的两个点$u,v$之间,用边权的两倍来更新答案。

      如果在图上DP,那么就相当于,将初始这些点权加入priority_queue,跑最短路即可。

      时间复杂度为$O(m log_2 n)$

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    const int N=2e5+10;
    struct rec{ int pre,to,w;}a[N<<1];
    int n,m,tot;
    bool inq[N];
    int head[N],d[N],val[N];
    namespace Fast_IO {
        inline int read() {
            int x=0,w=0; char c=0;
            while (c<'0'||c>'9') w|=c=='-',c=getchar();
            while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
            return w?-x:x;
        }
        void write(int x) {
            if (x<0) x=-x,putchar('-');
            if (x>9) write(x/10);
            putchar('0'+x%10);
        }
        void writeln(int x) {
            write(x); putchar('
    ');
        }
    };
    using namespace Fast_IO;
    void adde(int u,int v,int w) {
        a[++tot].pre=head[u];
        a[tot].to=v;
        a[tot].w=w*2;
        head[u]=tot;
    }
    struct Node {
        int id,val;
    };
    struct cmp {
        bool operator () (Node a,Node b) {
            return a.val > b.val;   
        }
    };
    priority_queue<Node,vector<Node>,cmp>q;
    void dijkstra() {
        for (int i=1;i<=n;i++) {
            d[i]=val[i];
            inq[i]=true;
            q.push((Node){i,val[i]});
        }
        while (q.size()) {
            int u=q.top().id; q.pop(); inq[u]=false;
            for (int i=head[u];i;i=a[i].pre) {
                int v=a[i].to; 
                if (d[v]>d[u]+a[i].w) {
                    d[v]=d[u]+a[i].w;
                    if (!inq[v]) q.push((Node){v,d[v]}); 
                }
            }
        }
    }
    signed main() {
        n=read();m=read(); 
        for (int i=1;i<=m;i++) {
            int u=read(),v=read(),w=read();
            adde(u,v,w); adde(v,u,w);
        }
        for (int i=1;i<=n;i++) val[i]=read();
        dijkstra();
        for (int i=1;i<n;i++) write(d[i]),putchar(' ');
        writeln(d[n]);
        return 0;
    }
    exciting.cpp

    Problem B 逮虾户

     要求的车速是一个大于等于0的值,设第$i$次估计的车速为$v_i$,走的路程为$s_i$,

      设$v'$表示真实速度,则有偏差值$d$的定义式为 $d = v' - v_i$。

      考虑对速度的估计的偏差值d每一次都恒定。

      给出$n$次测算的结果$s_i , v_i$,和这几次测试总共的用时$t$,输出$d$的值。

      对于$100\%$的数据满足$1 leq nleq 10^3,1 leq s_i leq 10^3 , |v_i| leq 10^3$

    Solution :

      考虑$t$这个函数是在$n+1$段不连续的定义域中单调减的。

      所以,我们可以做$n+1$二分,就能找到些定义域中和d最相近的。

    、 注意,最后统计答案的时候,需要check一下实际车速大于等于0.

      时间复杂度为$O(n ^2 log_2 S)$,其中$S$表示确定实数域大小。

    # include <bits/stdc++.h>
    using namespace std;
    const int N=1e3+10;
    const double eps = 1e-9;
    struct rec{double s,v;}a[N];
    int n,t;
    vector<double>ans;
    bool cmp (rec x, rec y) {
        return x.v>y.v;
    }
    double f (double x) {
        double res = 0;
        for (int i=1;i<=n;i++) res += (double)a[i].s/(double)(x+a[i].v);
        return res;
    }
    double work(double l,double r) {
        while (fabs(r-l)>=eps) {
            double mid = (l+r)/2.0;
            if (f(mid)<=t) r=mid;
            else l=mid; 
        }
        return l;
    }
    double calc(double x) {
        return fabs(f(x)-t);
    }
    int main() {
        scanf("%d%d",&n,&t);
        for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].s,&a[i].v);
        sort(a+1,a+1+n,cmp);
        double l=-1e9;
        for (int i=1;i<=n;i++) {
            ans.push_back(work(l,-a[i].v-eps));
            l=-a[i].v+eps;
        }
        ans.push_back(work(l,1e9));
        double res = ans[0], delta =calc(ans[0]);
        for (int i=1;i<ans.size();i++) {
            bool ok = true;
            for (int j=1;j<=n;j++) if (a[j].v+ans[i]<eps) {
                ok = false; break;
            }
            if (!ok) continue;
            double tmp = calc(ans[i]);
            if (tmp <= delta) {
                res = ans[i]; delta = tmp;
            }
        }
        printf("%.10lf
    ",res);
        return 0;
    }
    dejavu.cpp

    Problem C 跳一跳

      如果序列中任意相邻两个元素,都是极值点,其中一个是极大值点,另外一个极小值点。

       那么这个序列叫做波浪序列。

      给出对于长度为$n$序列,输出最长波浪序列的长度。

      对于$100\%$的数据满足 $1 leq n leq 10^5 , 1 leq a_i leq 10^9 $

    Solution :

      由于元素只进行比较,所以我们可以将其离散化。

      设$f[i][0]$表示第$i$个元素作为极小点为结尾的最长波浪序列长度,$f[i][1]$表示第$i$个元素作为极大点为结尾的最长波浪序列长度。

      转移方程为:$f[i][0] = max(f[j][1] + 1) (a_i < a_j) , f[i][1] = max (f[j][0] + 1) (a_i > a_j)$

      可以用值域线段树来维护这个$DP$。时间复杂度为$O(n log_2 n)$

    # include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    int a[N],n,f[N][2];
    vector<int>tmp;
    namespace Fast_IO {
        inline int read() {
            int x=0,w=0; char c=0;
            while (c<'0'||c>'9') w|=c=='-',c=getchar();
            while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
            return w?-x:x;
        }
        void write(int x) {
            if (x<0) x=-x,putchar('-');
            if (x>9) write(x/10);
            putchar('0'+x%10);
        }
        void writeln(int x) {
            write(x); putchar('
    ');
        }
    };
    using namespace Fast_IO;
    struct Segment_Tree {
        int tr[N<<2];
        # define ls (x<<1)
        # define rs (x<<1|1)
        # define mid (l+r>>1)
        # define lson ls,l,mid
        # define rson rs,mid+1,r
        void update(int x,int l,int r,int pos,int opx) {
            if (l==r) {
                tr[x]=max(tr[x],opx);
                return;
            }
            if (pos<=mid) update(lson,pos,opx);
            else update(rson,pos,opx);
            tr[x]=max(tr[ls],tr[rs]);
        }
        int query(int x,int l,int r,int opl,int opr) {
            if (opl<=l && r<=opr) return tr[x];
            int ret=0;
            if (opl<=mid) ret=max(ret,query(lson,opl,opr));
            if (opr>mid) ret=max(ret,query(rson,opl,opr));
            return ret;
        }
    }tr0,tr1;
    int main() {
        
        n=read();
        for (int i=1;i<=n;i++) {
            tmp.push_back(a[i]=read());
        }
        sort(tmp.begin(),tmp.end());
        tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
        int m = tmp.size();
        for (int i=1;i<=n;i++) {
            a[i]=lower_bound(tmp.begin(),tmp.end(),a[i])-tmp.begin()+1;
        }
        int ans = 0;
        for (int i=1;i<=n;i++) {
            f[i][0]=f[i][1]=1;
            if (a[i]-1>=1) f[i][1] = max(f[i][1],tr0.query(1,1,m,1,a[i]-1)+1);
            if (a[i]+1<=m) f[i][0] = max(f[i][0],tr1.query(1,1,m,a[i]+1,m)+1);
            ans = max(ans,max(f[i][0],f[i][1]));
            tr0.update(1,1,m,a[i],f[i][0]);
            tr1.update(1,1,m,a[i],f[i][1]);
        }
        writeln(ans);
        return 0;
    }
    jump.cpp
  • 相关阅读:
    Autofac
    MYSQL存储过程获取记录总数
    MYSQL通用存储过程
    判断用户用手机访问还是用电脑访问网页
    HttpRuntime.Cache与HttpContext.Current.Cache
    Eclipse之NDK编译-- Type 'jint' could not be resolved, and JNIEnv, jclass错误解决办法
    解决Android adjustresize全屏无效问题
    Android手机使用广播监听手机收到的短信
    使用Jackson解析首字母大写的json字符串
    Android Studio中设置提示函数用法
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11866620.html
Copyright © 2011-2022 走看看