zoukankan      html  css  js  c++  java
  • 2017北京国庆刷题Day1 afternoon

    期望得分:100+100+100=300

    实际得分:100+100+100=300

    T1 一道图论好题(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。

    最优解一定是一条边+两个点

    考场上是二分答案,然后枚举所有的边,只要有一个满足点-边*答案>=0 就return true

    std直接 ans=max(ans,(a[A]+a[B])/(C+0.0));

    #include<cmath> 
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 100001
    using namespace std;
    int n,m;
    int point[N];
    struct node
    {
        int u,v,w;
    }e[N];
    const double eps=1e-4;
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    bool check(double k)
    {
        for(int i=1;i<=m;i++)
            if(point[e[i].u]+point[e[i].v]-k*e[i].w>=0) return true; 
        return false;
    }
    int main()
    {
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        read(n); read(m);
        int maxn=0;
        for(int i=1;i<=n;i++) 
        {
            read(point[i]);
            maxn=max(maxn,point[i]);
        }
        int minn=1e9;
        for(int i=1;i<=m;i++)
        {
            read(e[i].u); read(e[i].v); read(e[i].w);
            minn=min(minn,e[i].w);
        }
        double l=0,r=maxn*2*1.0/minn,mid,ans;
        while(fabs(r-l)>eps)
        {
            mid=(l+r)/2;
            if(check(mid)) ans=mid,l=mid+eps;
            else r=mid-eps;
        }
        printf("%.2lf",ans);
    }
    View Code

    T2拍照(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

    样例解释

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

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

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

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

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

    枚举高度,贪心累计宽度

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 1001
    using namespace std;
    int n;
    int w[N],h[N],nw[N],nh[N],tmp[N];
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    int work(int maxh)
    {
        int change=0,tot=0;
        for(int i=1;i<=n;i++)
        {
            if(h[i]>maxh)
            {
                if(w[i]>maxh) return 0;
                if(change==n/2) return 0;
                change++; nw[i]=h[i]; nh[i]=w[i];
            } 
            else
            {
                nw[i]=w[i]; nh[i]=h[i];
                if(nw[i]>nh[i])
                {
                    if(nw[i]>maxh) continue;
                    tmp[++tot]=nw[i]-nh[i];
                }
            }
        }
        int sum=0;
        for(int i=1;i<=n;i++) sum+=nw[i];
        int res=n/2-change;
        sort(tmp+1,tmp+tot+1,greater<int>());
        for(int i=1;i<=res;i++) sum-=tmp[i];
        return sum;
    }
    int main()
    {
        freopen("photo.in","r",stdin);
        freopen("photo.out","w",stdout);
        read(n); 
        for(int i=1;i<=n;i++)
        {
            read(w[i]); read(h[i]);
        }
        int ans=1e9,t;
        for(int i=1;i<=1000;i++) 
        {
            t=work(i);
            if(t) ans=min(ans,i*t);
        }
        printf("%d",ans);
    }
    View Code

    T3或和异或(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。

    线段树,std倍增

    #include<cstdio>
    #include<iostream>
    #define N 131073
    using namespace std;
    int n,m;
    int sum[N<<2],mid[N<<2];
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    void build(int k,int l,int r,int dep)
    {
        if(l==r) { read(sum[k]); return; }
        mid[k]=l+r>>1;
        build(k<<1,l,mid[k],dep+1);
        build(k<<1|1,mid[k]+1,r,dep+1);
        if((n-dep+1)&1) sum[k]=(sum[k<<1]|sum[k<<1|1]);
        else sum[k]=(sum[k<<1]^sum[k<<1|1]);
    }
    void change(int k,int l,int r,int pos,int w,int dep)
    {
        if(l==r) { sum[k]=w; return; }
        if(pos<=mid[k]) change(k<<1,l,mid[k],pos,w,dep+1);
        else change(k<<1|1,mid[k]+1,r,pos,w,dep+1);
        if((n-dep+1)&1) sum[k]=(sum[k<<1]|sum[k<<1|1]);
        else sum[k]=(sum[k<<1]^sum[k<<1|1]);
    }
    int main()
    {
        freopen("xor.in","r",stdin);
        freopen("xor.out","w",stdout);
        read(n); read(m);
        int s=1<<n;
        build(1,1,s,1);
        int x,y;
        while(m--)
        {
            read(x); read(y);
            change(1,1,s,x,y,1);
            printf("%d
    ",sum[1]);
        }
    }
    View Code
  • 相关阅读:
    一个万能的工具包下载网站
    Keras框架简介
    发现了一个非常棒的pyqt5的例子集
    人脸识别常用数据集大全(12/20更新)
    用 opencv和numpy进行图片和字符串互转,并保存至 json
    机器学习中的范数规则化-L0,L1和L2范式(转载)
    利用face_recognition库裁取人脸
    一招解决C盘空间不足,再也不怕硬盘爆满!
    【LeetCode】394.字符串解码(辅助栈、递归、详细图解)
    程序员那些事儿:女婿程序员
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7617433.html
Copyright © 2011-2022 走看看