zoukankan      html  css  js  c++  java
  • test20190729 夏令营NOIP训练14

    40+100+0=140.

    基因光线

    黑大帅统治古古怪界后,一直在玩一种很奇葩的游戏。在一个二维平面上,他先复制了n个小A,把他们放在不同的位置,然后射出一条ax+by+c=0的基因光线,宽度为d,即离这条直线的距离不大于d的小A会被射中。当然,某些悲剧的小A就会被射中,并变成黑小A。当然,这不是重点。玩了很久后,黑大帅猛然发现,自己竟然一次都没有射中小A。黑大帅怒了,于是他开启了作弊模式,将c改成自己想要的任意数值。现在,黑大帅想知道,在开启了作弊模式后,他射出一道基因光线最多能击中几个小A。

    输入格式:
    第一行五个数字a,b,d,n,接下来n行每行两个数字x,y表示这个小A的坐标。

    输出格式:
    一行一个数字表示最多能击中几个小A。

    样例输入:
    1 -1 0.707106782 5
    0 0
    1 0
    0 1
    2 0
    2 1

    样例输出:
    4

    数据范围:
    50%的数据满足a=0;
    100%的数据满足n<=100000,其余所有数值均为绝对值不大于1000的实数。

    时间限制:
    1s
    空间限制:
    64M


    写了一个旋转扫描,炸了精度,WA成40.

    后来翻刘老爷的代码知道,可以直接计算三角函数值而不必先求角度再代函数。

    好朋友

    noip2011就要来了,W校的同学们不仅看重这次比赛,更看重noip2011和谁住在同一个房间。同学之间的关系好坏可以用一个亲密值表示,亲密值越大,两个同学关系越好。小A作为W校信息组的组长,自然想要让同学们在比赛前能好好休息,放松心情,让同学们在赛场上能够超常发挥。他现在知道自己预订的房间都是双人间,且知道这n个同学之间的关系。n个同学的关系可以用一个n条双向边的连通图来描述,即某个同学只愿意和与他有边相连的同学住同一个房间,边权即为两个同学的亲密值。数据保证没有重边、自环。现在小A想知道在让所有同学的要求满足的情况下,亲密值最低的一对同学亲密值最高是多少。

    输入格式:
    第一行一个正整数n,下面n行每行三个数u,v,w,表示u到v有一条边权为w的双向边。

    输出格式:
    假如无论如何都无法满足所有同学的要求,输出”no answer”,否则输出亲密值最低的一对同学的最高亲密值。

    样例输入:
    4
    1 2 3
    2 3 10
    3 4 3
    1 4 1

    样例输出:

    数据范围:
    50%的数据满足n<=20;
    80%的数据满足n<=1000;
    100%的数据满足n<=100000,-10^9<=w<=10^9

    时间限制:
    1S
    空间限制:
    64M

    题解

    先二分答案转化为判定问题,然后考虑怎么做。

    其实就是一个剥叶子的过程,类似拓扑排序。但要注意因为是基环树最后可能剩下一个环,所以还要判断环上点数的奇偶性。(O(nlog n))

    但是发现大家都是二分答案+二分图匹配,我不知道这(O(n^2 log n))是怎么过的。

    少数人写的(O(n))的剥叶子,考虑什么时候会有多解的情况,只有在环上的时候。而这个环的方案数只有2……

    砍树(2)

    小A是小B家的园丁。小B的家里有n棵树,第i棵树的横坐标为i。一天,小B交给小A一个任务,让他降低自己家中的某些树木的高度。这个任务对小A来说十分简单,因为他有一把极其锋利的斧头和一门独门砍树秘籍,能够轻易地砍断任何参天大树。小A的砍树方法有3种,都是沿着一条y=kx+b的直线砍一段区间的树,相同的方法k值相同。只用了一个下午,小A就完成了小B的任务。第二天,小B来视察小A的任务完成情况。小B想知道小A是否真的用心砍树,于是提出了q个询问,每次询问一段区间中最低的树的高度。小A当然是不会记住树木的砍伐情况的,他只知道自己按什么顺序,使用了什么方法,砍了哪个连续区间的树,而且区间都是互不包含的。现在小A想请你帮帮他,回答小B的询问。

    输入格式:
    第一行三个整数k1,k2,k3表示小A三种砍树方法的斜率值;
    第二行一个数n,表示一共有n棵树;
    第三行n个数hi,分别表示n棵树的高度;
    第四行一个数m,表示小A一共进行了m次操作;
    接下来m行,每行四个数L,R,p,b,表示用第p种方法,即用y=kp+b的直线砍[L,R]区间的树;
    接下来一行一个数q,表示小B的询问数;
    接下来q行,每行两个数L,R,表示询问[L,R]区间中最低的树的高度。

    输出格式:
    一共q行,每行一个数h表示对应的回答。

    样例输入:
    1 0 -1
    4
    10 30 20 1
    2
    3 4 2 5
    1 3 3 10
    2
    1 2
    2 3

    样例输出:

    数据范围:
    n<=1000000,m<=500000

    时间限制:
    3s
    空间限制:
    64M

    提示:
    如下图,红色即为树的剩余部分。

    题解

    暴力有60分,这边的人很大方。

    考场上感觉是一个维护下凸包的问题,然后觉得这扫描线实在难写,而我只剩下40分钟了,所以打了一个暴力。

    然后翻别人的代码,发现因为是先改后查,就对三个斜率分别维护纵截距最小值,然后全局统计一下就行了。线段树即可解决,感觉自己弱智++。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define rep(i,l,r) for(int i=(l);i<=(r);++i)
    #define per(i,r,l) for(int i=(r);i>=(l);--i)
    using namespace std;
    int k[3],val[2100005],b[2100005][3],h[1100005],l[2100005],r[2100005],n,m,q;
    const int INF=100000000;
    int build(int ll,int rr,int no){
        int mid=(ll+rr)>>1;l[no]=ll;r[no]=rr;
        b[no][0]=b[no][1]=b[no][2]=INF;
        if(ll==rr){return val[no]=h[ll];}
        int lc=no<<1,rc=lc+1;
        return val[no]=min(build(ll,mid,lc),build(mid+1,rr,rc));
    }
      
    void update(int no,int x,int y,int p,int bb){
        if(l[no]==x&&r[no]==y){b[no][p]=min(b[no][p],bb);return;}
        int mid=(l[no]+r[no]) >> 1,lc=no*2,rc=lc+1;
        if(x>mid){update(rc,x,y,p,bb);return;}
        if(y<=mid){update(lc,x,y,p,bb);return;}
        update(lc,x,mid,p,bb);update(rc,mid+1,y,p,bb);
        return;
    }
    void dfs(int no){
        int lc=no*2,rc=lc+1;
        if(l[no]!=r[no]){
            rep(i,0,2){
                int wa=b[no][i];
                b[lc][i]=min(b[lc][i],wa);
                b[rc][i]=min(b[rc][i],wa);
            }
            dfs(lc);dfs(rc);
            val[no]=min(val[lc],val[no]);
            val[no]=min(val[rc],val[no]);
        }
        else{
            rep(i,0,2){
                int wa=b[no][i];
                if(wa!=INF) val[no]=min(val[no],k[i]*r[no]+wa);
            }
        }
    }
    int query(int no,int x,int y){
        if(l[no]==x&&r[no]==y) return val[no];
        int mid=(l[no]+r[no])>>1;int lc=no*2,rc=lc+1;
        if(y<=mid) return query(lc,x,y);
        if(x>mid) return query(rc,x,y);
        return min(query(lc,x,mid),query(rc,mid+1,y));
    }
    int main()
    {
        scanf("%d%d%d",&k[0],&k[1],&k[2]);
        scanf("%d",&n);
        rep(i,1,n) scanf("%d",&h[i]);
        build(1,n,1);
        scanf("%d",&m);
        while(m--){
            int l,r,p,b;
            scanf("%d%d%d%d",&l,&r,&p,&b);
            update(1,l,r,p-1,b);
        }
        scanf("%d",&q);
        dfs(1);
        while(q--){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d
    ",query(1,l,r));
        }
    }
    
  • 相关阅读:
    [置顶] 寻找数组中的值
    详解 Java 的八大基本类型,写得非常好!
    从入门到放弃的 Java 架构师面试题!
    通往大牛之路,百度Java面试题前200页!
    HTML与CSS简单页面效果实例
    JS面向对象
    JS瀑布流效果
    CSS常用操作-图片
    CSS常用操作-导航栏
    CSS常用操作-对齐
  • 原文地址:https://www.cnblogs.com/autoint/p/test20190729.html
Copyright © 2011-2022 走看看