zoukankan      html  css  js  c++  java
  • 2017-10-1 清北刷题冲刺班p.m

    一道图论好题

    (graph)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

    LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,不仅有边权还有点权。

    LYK给出了一个子图的定义,一张图G’={V’,E’}被称作G的子图,当且仅当

    ·G’的点集V’包含于G的点集V。

    ·对于E中的任意两个点a,b∈V’,当(a,b)∈E时,(a,b)一定也属于E’,并且连接这两个点的边的边权是一样的。

    LYK给一个子图定义了它的价值,它的价值为:点权之和与边权之和的比。

    LYK想找到一个价值最大的非空子图,所以它来找你帮忙啦。

    输入格式(graph.in)

        第一行两个数n,m表示一张n个点m条边的图。

        第二行n个数ai表示点权。

        接下来m行每行三个数u,v,z,表示有一条连接u,v的边权为z的无向边。数据保证任意两个点之间最多一条边相连,并且不存在自环。

    输出格式(graph.out)

    你需要输出这个价值最大的非空子图的价值,由于它是一个浮点数,你只需要保留小数点后两位有效数字。

    输入样例

    3 3

    2 3 4

    1 2 3

    1 3 4

    2 3 5

    输出样例

    1.67

    样例解释

    选择1,2两个点,则价值为5/3=1.67。

    对于20%的数据n=2

    对于50%的数据n<=5

    对于100%的数据1<=n,m<=100000,1<=ai,z<=1000。

    /*
        最优比率环??根本不会
        经过证明,最终答案是只选择一条边,求一个最大值 
    */
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <complex>
    #include <string>
    #include <cstring>
    #include <vector>
    #include <map>
    using namespace std;
    double ans;
    int A,B,C,n,m,a[100005],i;
    int main()
    {
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (i=1; i<=n; i++) scanf("%d",&a[i]);
        for (i=1; i<=m; i++)
        {
            scanf("%d%d%d",&A,&B,&C);
            ans=max(ans,(a[A]+a[B])/(C+0.0));
        }
        printf("%.2f
    ",ans);
        return 0;
    }
    AC代码

    拍照

    (photo)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

        假设这是一个二次元。

    LYK召集了n个小伙伴一起来拍照。他们分别有自己的身高Hi和宽度Wi。

    为了放下这个照片并且每个小伙伴都完整的露出来,必须需要一个宽度为ΣWi,长度为max{Hi}的相框。(因为不能叠罗汉)。

    LYK为了节省相框的空间,它有了绝妙的idea,让部分人躺着!一个人躺着相当于是身高变成了Wi,宽度变成了Hi。但是很多人躺着不好看,于是LYK规定最多只有n/2个人躺着。(也就是说当n=3时最多只有1个人躺着,当n=4时最多只有2个人躺着)

    LYK现在想问你,当其中部分人躺着后,相框的面积最少是多少。

    输入格式(photo.in)

        第一行一个数n。

        接下来n行,每行两个数分别是Wi,Hi。

    输出格式(photo.out)

    你需要输出这个相框的面积最少是多少。

    输入样例

    3

    3 1

    2 2

    4 3

    输出样例

    21

    样例解释

    如果没人躺过来,需要27的面积。

    我们只要让第1个人躺过来,就只需要21的面积!

    对于30%的数据n<=10。

    对于60%的数据n<=1000,Wi,Hi<=10。

    对于100%的数据1<=n,Wi,Hi<=1000。

    /*
        贪心
        枚举最终状态最高身高为x
        分三种情况
        1.身高>x,宽度<=x,一定躺 
        2.身高<=x,宽度>x,一定不躺
        3.身高,宽度<=x
            1)身高>宽度 不能躺 
            2)身高<=宽度 只能让部分人躺,(宽度-身高)越大,越要躺 
    */
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <map>
    using namespace std;
    set<int> ::iterator sit;
    int ans,sum,p[1005],i,a[1005],b[1005],cnt,CNT,j,ANS,n;
    int cmp(int i,int j) {return i>j;}
    bool FLAG;
    int main()
    {
        freopen("photo.in","r",stdin);
        freopen("photo.out","w",stdout);
        ANS=1000000000;
        scanf("%d",&n);
        for (i=1; i<=n; i++)
          scanf("%d%d",&a[i],&b[i]);
        for (i=1; i<=1000; i++)
        {
            sum=0; FLAG=true; cnt=0; CNT=0;
            for (j=1; j<=n; j++)
              if (b[j]<=i && (a[j]<=b[j] || a[j]>i)) sum+=a[j]; else
                if (a[j]>i && b[j]>i) {FLAG=false; break;} else
                  if (b[j]>i) {cnt++; sum+=b[j];} else
                  {
                      p[++CNT]=a[j]-b[j];
                      sum+=a[j];
                  }
            if (!FLAG) continue;
            if (cnt>n/2) continue;
            sort(p+1,p+CNT+1,cmp);
            for (j=1; j<=min(n/2-cnt,CNT); j++) sum-=p[j];
            ANS=min(ANS,sum*i);
        }
        cout<<ANS;
        return 0;
    }
    AC代码 贪心

    或和异或

    (xor)

    Time Limit:2000ms   Memory Limit:128MB

    题目描述

    LYK最近在研究位运算,它研究的主要有两个:or和xor。(C语言中对于|和^)

    为了更好的了解这两个运算符,LYK找来了一个2^n长度的数组。它第一次先对所有相邻两个数执行or操作,得到一个2^(n-1)长度的数组。也就是说,如果一开始时a[1],a[2],…,a[2^n],执行完第一次操作后,会得到a[1] or a[2],a[3] or a[4] ,…, a[(2^n)-1] or a[2^n]。

    第二次操作,LYK会将所有相邻两个数执行xor操作,得到一个2^(n-2)长度的数组,假如第一次操作后的数组是b[1],b[2],…,b[2^(n-1)],那么执行完这次操作后会变成b[1] xor b[2], b[3] xor b[4] ,…, b[(2^(n-1))-1] xor b[2^(n-1)]。

    第三次操作,LYK仍然将执行or操作,第四次LYK执行xor操作。如此交替进行。

    最终这2^n个数一定会变成1个数。LYK想知道最终这个数是多少。

    为了让这个游戏更好玩,LYK还会执行Q次修改操作。每次修改原先的2^n长度的数组中的某一个数,对于每次修改操作,你需要输出n次操作后(最后一定只剩下唯一一个数)剩下的那个数是多少。

    输入格式(xor.in)

        第一行两个数n,Q。

    接下来一行2^n个数ai表示一开始的数组。

    接下来Q行,每行两个数xi,yi,表示LYK这次的修改操作是将a{xi}改成yi。

    输出格式(xor.out)

    Q行,表示每次修改操作后执行n次操作后剩下的那个数的值。

    输入样例

    2 4

    1 6 3 5

    1 4

    3 4

    1 2

    1 2

    输出样例

    1

    3

    3

    3

    样例解释

    第一次修改,{4,6,3,5}->{6,7}->{1}

    第二次修改,{4,6,4,5}->{6,5}->{3}

    第三次修改,{2,6,4,5}->{6,5}->{3}

    第四次修改,{2,6,4,5}->{6,5}->{3}

    对于30%的数据n<=17,Q=1。

    对于另外20%的数据n<=10,Q<=1000。

    对于再另外30%的数据n<=12,Q<=100000。

    对于100%的数据1<=n<=17,1<=Q<=10^5,1<=xi<=2^n,0<=yi<2^30,0<=ai<2^30。

    /*
        倍增表
        st[j][i]表示i次操作后,j位置的数字是什么 
    */
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <algorithm>
    #include <string>
    #include <cstring>
    using namespace std;
    long long st[131073][18];
    int next[18][131073],i,j,n,m,now,k,A,B;
    int main()
    {
        freopen("xor.in","r",stdin);
        freopen("xor.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (i=1; i<=(1<<n); i++) cin>>st[i][0];
        for (i=1; i<=n; i++)
        {
            for (j=1; j<=(1<<n); j+=(1<<i))
            {
                if (i % 2==1) st[j][i]=st[j][i-1]|st[j+(1<<(i-1))][i-1]; else
                  st[j][i]=st[j][i-1]^st[j+(1<<(i-1))][i-1];
            }
        }
        for (i=1; i<=n; i++)
          for (j=1; j<=(1<<n); j+=(1<<i))
          {
              for (k=j; k<=j+(1<<i)-1; k++)
                next[i][k]=j;
          }
        for (i=1; i<=m; i++)
        {
            scanf("%d%d",&A,&B);
            st[A][0]=B;
            for (j=1; j<=n; j++)
            {
                now=next[j][A];
                if (j % 2==1) st[now][j]=st[now][j-1]|st[now+(1<<(j-1))][j-1]; else
                    st[now][j]=(st[now][j-1]^st[now+(1<<(j-1))][j-1]);
            }
            cout<<st[1][n]<<endl;
        }
        return 0;
    }
    AC代码 倍增表
  • 相关阅读:
    面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
    JAVA 线上故障排查套路,从 CPU、磁盘、内存、网络到GC 一条龙!
    面经分享:看非科班研究生如何转行斩获 ATM 大厂的 Offer ?
    Jmeter JDBC配置
    Jmeter JDBC连接
    js基础用法1
    java实现io读取数据
    mysql语句
    java修改linux文件
    linux永久或临时修改dns
  • 原文地址:https://www.cnblogs.com/thmyl/p/7617322.html
Copyright © 2011-2022 走看看