zoukankan      html  css  js  c++  java
  • [SinGuLaRiTy] 2017-07-21 综合性测试

    【SinGuLaRiTy-1028】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

    对于所有题目:Time Limit: 1s | Memory Limit: 256MB

    [USACO2016 Jan] 愤怒的奶牛 (Angry Cows)

    题目描述

    在数轴x上摆放有n(2<=n<=50000)捆干草堆,没有任何两堆在同样的位置,所有的位置均为整数。你可以用弹弓射击射击数轴上的任意地点。如果你用弹弓以R的力度射击x处,那么该处会发生爆炸,爆炸的范围是以R为半径的圆形区域,所以它会使得[x-R,x+R]的所有干草堆同时发生爆炸。这些干草堆的爆炸半径是R-1。它们又会触发连锁反应,第三轮的爆炸的半径为R-2,依次递减。请选择最小的力度射击,使得所有的干草堆全部爆炸。

    输入

    第一行包含N。接下来N个整数,表示干草堆的位置。所有位置在[0,1000000000]内。

    输出

    输出最小的力度R,使得所有的干草堆发生爆炸。四舍五入保留一位小数。

    样例数据

    样例输入 样例输出

    5
    8
    10
    3
    11
    1

    3.0

     

     

     

     

     

     

    <样例解释>

    如果以力度3射击坐标5,则坐标3,坐标8处的干草堆会发生爆炸,然后又会引爆坐标1和坐标10的干草堆,最后引爆坐标11处的干草堆。

    解析

    f[i]表示要炸掉i之前的所有干草堆,在i点最少需要的半径。
    g[i]表示要炸掉i之后的所有干草堆,在i点最少需要的半径。
    找到满足(j<i&&a[i]-a[j]>f[j]+1)的最后一个j,f[i]=min(a[i]-a[j],f[j+1]+1),g数组同理。
    最后枚举起始的射击区间,计算答案。
    由于答案的小数部分只可能是0或者0.5,所以将所有数乘以2就可以避免小数问题,最后答案再除以2就可以了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    
    #define ll long long
    #define N 50005
    #define inf 2000000000
    
    using namespace std;
    
    int n,a[N],f[N],g[N];
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]*=2;
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)
            f[i]=g[i]=inf;
        int t=1;
        f[1]=0;
        for(int i=2;i<=n;i++)
        {
            while(t+1<i&&a[i]-a[t+1]>f[t+1]+2)
                t++;
            f[i]=min(a[i]-a[t],f[t+1]+2);
        }
        t=n;
        g[n]=0;
        for(int i=n-1;i>=1;i--)
        {
            while(t-1>i&&a[t-1]-a[i]>g[t-1]+2)
                t--;
            g[i]=min(a[t]-a[i],g[t-1]+2);
        }
        int ans=inf;
        for(int i=1,j=n;i<j;)
        {
            ans=min(ans,max((a[j]-a[i])/2,max(f[i],g[j])+2));
            if(f[i+1]<g[j-1])
                i++;
            else
                j--;
        }
        printf("%.1lf",(double)ans/2);
        return 0;
    }

    [USACO2016 Jan] 无线电通信 (Radio Contact)

    题目描述

    农夫约翰和奶牛贝西要去寻找丢失的奶牛,为了彼此能联系对方,他们带着无线电通讯设备。不幸的是电池快没有电了。所以它们要尽量节省电能。农夫从位置(fx,fy)出发,一共走N步,贝西从位置(bx,by)出发,一共走M步。农夫的路线是由一个长度为N的字符串限制,字符串只出现’E’或’S’或’W’或’N’中,表示东南西北四个方向。农夫每一单位时间可以选择不动,或者按照限制走出一步。奶牛贝西也是如此。现在无线电设备每一单位时间消耗的电量等于他们的距离的平方。请问,他们走到终点,最少消耗多少电量?

    输入

    第一行两个整数n,m(1<=n,m<=1000),第二行为fx,fy表示农夫的起始位置,第三行为bx,by,表示贝西的起始位置。
    接下来有两个字符串,第一个字符串表示农夫的路线,第二个字符串表示贝西的路线。
    他们的坐标总是在(0<=x,y<=1000)。北是y的正方向,东为x的正方向。

    输出

    输出一个整数,表示最少消耗的电量。

    样例数据

    样例输入 样例输出

    2 7
    3 0
    5 0
    NN
    NWWWWWN

    28

    解析

    其实,这是一道水题。
    设f[i][j]表示当前第一个人走了i步第二个人走了j步,那么就有f[i+1][j]=min(f[i+1][j],f[i][j]+dis())。然后f[i][j+1]和f[i+1][j+1]用同样的方法推出来。

    Code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    
    #define N 1024
    
    typedef long long ll;
    
    using namespace std;
    
    int n,m,a[N][2],b[N][2];
    ll f[N][N];
    char s[N];
    
    inline int dis(int a,int b,int c,int d)
    {
         return (c-a)*(c-a)+(b-d)*(b-d);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        cin>>a[1][0]>>a[1][1]>>b[1][0]>>b[1][1];
        scanf("%s",s+1);
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='N')
                a[i+1][0]=a[i][0],a[i+1][1]=a[i][1]+1;
            else if(s[i]=='S')
                a[i+1][0]=a[i][0],a[i+1][1]=a[i][1]-1;
            else if(s[i]=='W')
                a[i+1][0]=a[i][0]-1,a[i+1][1]=a[i][1];
            else if(s[i]=='E')
                a[i+1][0]=a[i][0]+1,a[i+1][1]=a[i][1];
        }
        scanf("%s",s+1);
        for(int i=1;i<=m;i++)
        {
            if(s[i]=='N')
                b[i+1][0]=b[i][0],b[i+1][1]=b[i][1]+1;
            else if(s[i]=='S')
                b[i+1][0]=b[i][0],b[i+1][1]=b[i][1]-1;
            else if(s[i]=='W')
                b[i+1][0]=b[i][0]-1,b[i+1][1]=b[i][1];
            else if(s[i]=='E')
                b[i+1][0]=b[i][0]+1,b[i+1][1]=b[i][1];
        }
        for(int i=1;i<=n+1;i++)
            for(int j=1;j<=m+1;j++)
                f[i][j]=2147483647;
        f[1][1]=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                f[i+1][j]=min(f[i+1][j],f[i][j]+dis(a[i+1][0],a[i+1][1],b[j][0],b[j][1]));
                f[i][j+1]=min(f[i][j+1],f[i][j]+dis(a[i][0],a[i][1],b[j+1][0],b[j+1][1]));
                f[i+1][j+1]=min(f[i+1][j+1],f[i][j]+dis(a[i+1][0],a[i+1][1],b[j+1][0],b[j+1][1]));
            }
        printf("%I64d",f[n+1][m+1]);
        return 0;
    }

    [USACO2016 Jan] 熄灯 (Lights Out)

    题目描述

    谷仓是一个简单的多边形。它的每一条边或平行于x轴,或平行于y轴。从任意一个点沿顺时针方向走,横边和纵边是交替出现的。多边形一共有n个点,编号为1到n。其中1号点为出口。奶牛贝西已经完全记住了谷仓的地图。它从某一个点出发,只能沿着边界走,在开灯的情况,它能很快知道怎么走才能更快到达出口。可是有一天,灯熄灭了。它一下慌了神,然后它忘了自己在哪个点了。但是幸运的是它仍然记得整个谷仓的地图,而且它能够凭触觉知道当前点的内角有多大,它也能感觉到当前点是不是出口,而且经过一条边后也能精确地计算出该边的长度。现在,为了寻找出口,它决定采取这样的策略:沿着顺时针方向继续走下去,直到它能够判断出自己的位置,然后再选择距离最短的方向(顺时针或逆时针)走到出口。求最坏的情况下,贝西走到出口要比灯没坏的情况下多花多少时间。

    输入

    第一行包含N(4<=N<=200),接下来N行每行包含两个整数,表示多边形的n个顶点(xi,yi),按顺时针的方向给出。这些点的范围均在[-100000,100000]

    输出

    输出贝西按照上述策略在最坏情况下比正常情况下要多花的时间。

    样例数据

    样例输入 样例输出

    4
    0 0
    0 10
    1 10
    1 0

    2

     

     

     

     

     

     

    <样例解释>

    贝西如果在出口处(Point 1),肯定可以感知到,这绝对不会是最坏情况。现在考虑它在其他3个点时的情形:它当前可以感知到内角的大小。但因为内角都是90度,所以他无法确定自己位置。于是它按照既定的策略,顺时针走:
    1.如果它在开始在点2,它需要走到点3,此时,它知道自己在哪里了。于是它找最短的路径,不管哪边,都是11.所以,它一共需要走12个单位。如果是开灯的情况下,只需要走10个单位。所以,它要多走两个单位。
    2.如果它在点3,它要走11个单位。开灯的情况下也要走11个单位。
    3.如果它在点4,它要走1个单位。开灯的情况下也要走1个单位。
    于是最坏的情况下,它要多走两个单位。

    解析

    这道题,其实最重要的就是贝西判定当前的位置的方法:通过走过一段独一无二的路线。那么,我们怎么用代码进行实现呢?在这里,我用的是vector套pair,这样写也显得有些混乱;有一种用hash来判断的方法,相比之下还是好理解一点。(hash是一个很重要的东西,以后的字符串处理常常会用到) 大体思路就是通过用角度的大小(90度和270度)和边的长度来表达区分不同的路线,如果这个特征值一样,我们就认为贝西无法区分,也就找不到自己的位置;如果特征值不同,贝西就可以辨别出方向了。需要注意的是:数据的处理以及表达方式一定要确保能描述每一条路线的特征,而不会出现不同的路线有相同特征值的情况。

    Code

    #include<iostream>
    #include<vector>
    #include<set>
    #include<algorithm>
    #include<cstdio>
    
    #define MAXN 210
    
    using namespace std;
    
    int opt[MAXN];
    
    int main()
    {
        int N;
        scanf("%d",&N);
        vector<pair<long long,long long> > A(N);
        for(int i=0;i<N;i++)
        {
            cin>>A[i].first>>A[i].second;
        }
        vector<int> S(1,0);
        for(int i=0;i<N;i++)
        {
            int j=(i+1)%N;
            int k=(i+2)%N;
            S.push_back(abs(A[i].first-A[j].first)+abs(A[i].second-A[j].second));
            if((A[i].first-A[j].first)*(A[k].second-A[j].second)-(A[k].first-A[j].first)*(A[i].second-A[j].second)>0)
                S.push_back(-1);
            else
                S.push_back(-2);
        }
        S.back()=0;
        for(int i=0;i<N;i++)
        {
            opt[i+1]=opt[i]+S[i*2+1];
        }
        opt[N]=0;
        for(int i=N-1;i>=0;i--)
        {
            opt[i]=min(opt[i],opt[i+1]+S[i*2+1]);
        }
        multiset<vector<int> > st;
        for(unsigned int i=0;i<S.size();i+=2)
        {
            for(unsigned int ln=1;i+ln<=S.size();ln+=2)
            {
                st.insert(vector<int>(S.begin()+i,S.begin()+i+ln));
            }
        }
        int result=0;
        for(unsigned int i=2;i+2<S.size();i+=2)
        {
            int ln;
            int cost=0;
            for(ln=1;;ln+=2)
            {
                if(st.count(vector<int>(S.begin()+i,S.begin()+i+ln))==1)
                    break;
                cost+=S[i+ln];
            }
            result=max(result,cost+opt[(i+ln)/2]-opt[i/2]);
        }
        cout<<result;
        return 0;
    }

    [Vijos 1157] 分梨子

    题目描述

    Finley家的院子里有棵梨树,最近收获了许多梨子。于是,Finley决定挑出一些梨子,分给幼稚园的宝宝们。可是梨子大小味道都不太一样,一定要尽量挑选那些差不多的梨子分给孩子们,那些分到小梨子的宝宝才不会哭闹。每个梨子都具有两个属性值,Ai和Bi,本别表示梨子的大小和甜度情况。假设在选出的梨子中,两个属性的最小值分别是A0和B0。只要对于所有被选出的梨子i,都满足C1*(Ai-A0)+C2*(Bi-B0)≤C3(其中,C1、C2和C3都是已知的常数),就可以认为这些梨子是相差不多的,可以用来分给小朋友们。那么,作为幼稚园园长的你,能算出最多可以挑选出多少个梨子吗?

    输入

    第一行一个整数N(1≤N≤2000),表示梨子的总个数。 第二行三个正整数,依次为C1,C2和C3(C1,C2≤2000,C3≤10^9)。 接下来的N行,每行两个整数。第i行的两个整数依次为Ai和Bi。

    输出

    只有一个整数,表示最多可以选出的梨子个数。

    样例数据

    样例输入 样例输出

    3
    2 3 6
    3 2
    1 1
    2 1

    2

    解析

    神奇的题~

    对于这道题,我们要采用"数形结合"的思想:每一个梨子不是有两个特征值Ai和Bi吗,我们要把它们看做一组坐标(Ai,Bi),这样一来,每个梨子就变为了坐标轴上的一个点。我们来继续处理给出的题目信息:在选出的梨子里,有两个最小值,也就是说,对于所有我们选中的梨子,都满足:Ai>A0,Bi>B0,也就是说,所有的我们选中的梨子所代表的的点,都应该位于直线x=A0的右边,直线y=B0的上方。<是不是很"神奇"?>我们继续,题目又说了:每一个梨子(点)都满足C1*(Ai-A0)+C2*(Bi-B0)≤C3,我们用更"数学"的语言翻译一下,就变成:“每一个点(X,Y)都满足M*(X-a)+N(Y-b)≤C (M,N,C均为常数,我们在这里也暂且把a和b当做常数)”,嘿,这不是高中数学教材里的线性规划不等式吗?下面我们来画一画图(图中的点代表梨子):

    如图,三条直线围成的这个直角三角形内的点就是我们能够选择的梨子了。欢呼了?雀跃啦?不行,现在直接枚举A0、B0,就已经是O(n^2)了,然后再在三角形里面扫描满足条件的梨子,O(n^3)直接超时。于是乎,我们要想一个法子,让扫描梨子这一项的工程量减小一点。我们先将原来的不等式变为:C1Ai+C2Bi-C3<=C1A0+C2B0 。然后我们可以这么搞:先在外层来一个for循环确定A0,接下来我们再由低到高枚举B0,这时看一看我们刚刚得出的不等式,发现等式右边的值变大了,也就是说会有新的梨子满足这个不等式。——哎,有法子了!我们在枚举A0、B0之前预处理一下:1>记录每一个y轴(y=1,y=2,y=3......)上的梨子(点)的数量,2>将梨子(点)按C1Ai+C2Bi-C3排序。我们在枚举B0的过程中,先删去由于B0增大而从三角形下方剔除出去的梨子(由于有了<1>预处理,这个过程就是O(1)的了),再加上新的满足不等式的值(<2>预处理也大大见减少了时间),不断更新,然后取最大值,最后就能得到答案了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std; const int MAXN=2005;
    struct node { int a,b,s; }p[MAXN];
    int c1,c2,c3; int ans; int n; inline bool cmp(const node&a,const node&b) { return a.s<b.s; } void init() { scanf("%d",&n); scanf("%d%d%d",&c1,&c2,&c3); for(int i=1;i<=n;i++) { scanf("%d%d",&p[i].a,&p[i].b); p[i].s=p[i].a*c1+p[i].b*c2; } } int main() { init(); sort(p+1,p+n+1,cmp); for(int i=1;i<=n;i++) { int a0=p[i].a; int b0=p[i].b; int cur=i; int tot=0; while(p[cur++].s<=c1*a0+c2*b0+c3&&cur<=n) tot++; ans=max(ans,tot); } cout<<ans<<endl; return 0; }

    Time: 2017-07-21

  • 相关阅读:
    .Net在线付款Paypal在线付款开发过程
    IE6.0 DIV层被SELECT遮挡的问题以及解决方案
    關於Nhibernate聯合主鍵的配置
    ASIHTTPRequest详解
    ArrayList IndexOf
    PLIST 读写
    iOS开发中的键盘高度变化处理
    IOS 数字键盘添加“完成”按钮
    Xcode解决error: PCH file built from a different branch ((clang425.0.27))
    IOS OPENURL调用第三方APP
  • 原文地址:https://www.cnblogs.com/SinGuLaRiTy2001/p/7218156.html
Copyright © 2011-2022 走看看