zoukankan      html  css  js  c++  java
  • 奶牛题题解

    这三道题一定来自USACO,因为USACO就乐意出奶牛的题。

    T1 奶牛晒衣服

    【问题描述】

        在熊大妈英明的带领下,时针和他的同伴生下了许多牛宝宝。熊大妈决定给每个宝宝都穿上可爱的婴儿装。于是,为牛宝宝洗晒衣服就成了很不爽的事情。
        圣人王担负起了这个重任。洗完衣服后,你就要弄干衣服。衣服在自然条件下用 1 的时间可以晒干 A 点湿度。抠门的熊大妈买了 1 台烘衣机。使用烘衣机可以让你用 1 的时间使 1件衣服除开自然晒干的 A 点湿度外,还可烘干 B 点湿度,但在 1 的时间内只能对 1 件衣服使用。
        N 件的衣服因为种种原因而不一样湿,现在告诉你每件衣服的湿度,要你求出弄干所有衣服的最少时间(湿度为 0 为干)。
    

    【输入格式】

    第一行 N , A , B ,接下来N行,每行一个数,表示衣服的湿度(1<= 湿度,A,B<=500000,1<=N<=500000)。

    【输出格式】

    一行,最少时间。

    【输入样例】

    Dry.in
    3 2 1
    1
    2
    3
    

    【输出样例】

    Dry.out
    1
    

    【样例解析】

        第 1 个时间内,用机器处理第 3 件衣服,此外,所有衣服自然晒干 2。花费 1 时间全部弄干。
    

    我的方法:

        通过观察样例和题面不难发现,这是一道贪心题。我们只要想出正确的贪心策略,再模拟一下就可以了。
        可行的贪心策略是:每次取湿度最大的衣服用烘干机晾干,直到所有衣服被晾干。
        注意,不要每次都sort一遍,会浪费时间,要用优先队列。因为sort是将整个序列排一遍序,在algorithm头文件中,他的时间复杂度为稳定的O(nlogn),而在优先队列中,插入一个元素并把它排好序的时间复杂度的时间为O(logn),所以快很多。
    

    另一种方法

        设a[i]为第i件衣服的湿度,当前答案范围是[L,R]。(一开始答案范围是[1,500000])
        先二分一个答案ans,然后枚举每件衣服,若a[i]<=ans*A,则表示第i件衣服可以自然晒干,否则表示需要用(a[i]-ans*A)/B(取上整)个单位时间的烘衣机,我们用time累计烘衣机所用的时间。
        若最后time<=ans,则表示该答案可行,更新答案,并继续在[L,ans-1]内进行二分答案。
        若最后time>ans,则表示该答案不行,继续在[ans+1,R]内进行二分答案。
        直到L>R停止。
    

    我的代码:

        //Powered by Dev C++ 2018/3/10 08:21
        #include<cstdio>
        #include<algorithm>
        #include<queue>
        using namespace std;
        int k,a,b,c,n;
        int flag=0;
        int time=0;
        int standard;
        int main()
        {
            priority_queue <int> gar;
        //    freopen("dry.in","r",stdin);
        //    freopen("dry.out","w",stdout);
            scanf("%d%d%d",&n,&a,&b);
            c = a + b;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&k);
                gar.push(k);
            }
            while(!gar.empty())
            {    
                k = gar.top();
                if(k <= standard) break;
                gar.pop();
                k -= b;
                standard += a;
                gar.push(k);
                time++;
            }
            printf("%d",time);
            return 0;
        }

    T2 奶牛排队

    【问题描述】

        奶牛在熊大妈的带领下排成了一条直队。
        显然,不同的奶牛身高不一定相同……
        现在,奶牛们想知道,如果找出一些连续的奶牛,要求最左边的奶牛 A 是最矮的,最右边的 B 是最高的,且 B 高于 A 奶牛,且中间如果存在奶牛,则身高不能和 A、B 奶牛相同,问这样的一些奶牛最多会有多少头。
        从左到右给出奶牛的身高,请告诉它们符合条件的最多的奶牛数(答案可能是零、二,但不会是一)。
    

    【输入格式】

        第一行一个数 N(2<=N<=100000),表示奶牛的头数。
        接 下 来 N 个 数 ,每 行 一 个数 , 从 上 到下 表 示 从左 到 右 奶牛 的 身 高 (1<=身高<=maxlongint)。
    

    【输出格式】

        一行,表示最多奶牛数。
    

    【输入样例】

    Tahort.in
    5
    1
    2
    3
    4
    1
    

    【输出样例】

    Tahort.out
    4
    

    【样例解析】

    取第 1 头到第 4 头奶牛,满足条件且为最多。

    题解方法:

        题外话:这道题貌似正解是单调栈……只是不知道怎么写,反正Drug是按这个方法讲给我的,但是我没听懂,不过下面的题解很易懂。
        对于奶牛的高度序列从L到R,我们可以找出序列中最小高度的奶牛编号min(若有多个,取编号大的)和最大高度的奶牛编号max(若有多个,取编号小的)。那么我们最终的答案序列一定不会跨过这两个奶牛,否则就不是可行序列了。所以整个序列被我们分成了三个部分。
        若min<max,则从min到max就是一个可行的序列,用(max-min+1)更新答案,并将[L,min-1]与[max+1,R]分别递归求解。如下图:
    
        若min>max,则将[L,max],[max+1,min-1],[min,R]三部分分别进行递归求解。如下图:
    
        那么现在的问题就是如何尽量快地找出一段序列的最小值与最大值,这是个经典的RMQ问题,使用ST算法。
        用f[i][j]表示从i开始长度为2j的一段中的最小值,那么:
        f[i][0] = a[i](a[i]表示原序列)
        f[i][j] = min{f[i][j-1], f[i+2j-1][j-1]}
        用动规便可求出f[i][j]。那么当我们要求[L,R]段的最小值时,就直接可以算出为:
        min{f[L][Len], f[R-2Len+1][Len]}(其中Len=trunc(log2(R-L+1)))
        f[i][j]的状态量为O(nlog2n),所以我们预处理f[i][j]的时间复杂度为O(nlog2n)。求一段中的最小值时我们就只需要O(1)的时间便可以算出。递归求序列最多有n层,所以总时间复杂度为O(nlog2n+n)。
    

    参考代码:

    //Powered by Dev C++ 2018/3/10 09:11
    #include<cstdio>
    #include<algorithm>
    typedef long long ll;
    using namespace std;
    ll a[100000],b[5000000],c[5000000];
    ll n,i,maximum;
    
    ll bub(ll k,ll l,ll r)
    {
        ll o,q,w;
        o = (l + r) / 2;
        if (l == r)
            b[k] = l;
        else
        {
            q = bub(k*2,l,o);
            w = bub(k*2+1,o+1,r);
            if(a[q] > a[w])
                b[k] = q;
            else
                b[k] = w;
        }
        return b[k];
    }
    
    ll bus(ll k,ll l,ll r)
    {
        ll o,q,w;
        o = (l + r) / 2;
        if (l == r)
            c[k] = l;
        else
        {
            q = bus(k*2,l,o);
            w = bus(k*2+1,o+1,r);
            if(a[q] < a[w])
                c[k] = q;
            else
                c[k] = w;
        }
        return c[k];
    }
    
    ll fb(ll k,ll l,ll r,ll x,ll y)
    {
        ll o,q,w;
        o = (l + r) / 2;
        if(x <= b[k] && y >= b[k])
            return b[k];
        else
        {
            if(y <= o)
                return fb(k*2,l,o,x,y);
            else if(x > o)
                return fb(k*2+1,o+1,r,x,y);
            else
            {
                q = fb(k*2,l,o,x,o);
                w = fb(k*2+1,o+1,r,o+1,y);
                if(a[q] > a[w])
                    return q;
                else
                    return w;
            }
        }
    }
    
    ll fs(ll k,ll l,ll r,ll x,ll y)
    {
        ll o,q,w;
        o = (l + r) / 2;
        if(x <= c[k] && y >= c[k])
            return c[k];
        else
        {
            if(y <= o)
                return fs(k*2,l,o,x,y);
            else if(x > o)
                return fs(k*2+1,o+1,r,x,y);
            else
            {
                q = fs(k*2,l,o,x,o);
                w = fs(k*2+1,o+1,r,o+1,y);
                if(a[q] < a[w])
                    return q;
                else
                    return w;
            }
        }
    }
    void work(ll l,ll r)
    {
        ll x,y;
        if(l >= r) return;
        x = fs(1,1,n,l,r);
        y = fb(1,1,n,l,r);
        if(y > x)
        {
            if(y-x > maximum) maximum = y - x;
            if(x-l > 1 + maximum) work(l,x-1);
            if(r-y > 1 + maximum) work(y+1,r);
        }
        else if(y < x)
        {
            if(y-1 > maximum) work(l,y);
            if(x-y > maximum + 2) work(y+1,x-1);
            if(r-x > maximum) work(x,r);
        }
    }
    int main()
    {
    //    freopen("tahort.in","r",stdin);
    //    freopen("tahort.out","w",stdout);
        scanf("%lld",&n);
        maximum = 1;
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
        }
        bub(1,1,n);
        bus(1,1,n);
        if(n > 1)
            work(1,n);
        printf("%lld",maximum+1);
        return 0;
    }

    T3 圆圈舞蹈

    【问题描述】

        熊大妈的奶牛在时针的带领下,围成了一个圈跳舞。由于没有严格的教育,奶牛们之间的间隔不一致。奶牛想知道两只最远的奶牛到底隔了多远。奶牛 A 到 B 的距离为 A 顺时针走和逆时针走,到达 B 的较短路程。告诉你相邻个奶牛间的距离,请你告诉奶牛两只最远的奶牛到底隔了多远。
    

    【输入格式】

        第一行一个整数 N,表示有 N 只奶牛。(2<=N<=100000)
        接下来 2~N+1 行,第 I 行有一个数,表示第 I-1 头奶牛顺时针到第 I 头奶牛的距离。(1<= 距离<=maxlongint,距离和<=maxlongint)
        第 N+1 行的数表示第 N 头奶牛顺时针到第 1 头奶牛的距离
    

    【输出格式】

    一行,表示最大距离。

    【输入样例】

    Circle.in
    5
    1
    2
    3
    4
    5
    

    【输出样例】

    Circle.out
    7
    

    解析:

        这道题需要算法优化。
        最笨的方法:多源最短路Floyd,或者从每头牛开始枚举与其他牛的距离,再枚举找到最大距离。时间复杂度是o(n^3),显然不合适。然而我过了四个点(划死。
        正确解法:其实我们并不需要知道所有奶牛之间的距离,我们只需要知道对于每头奶牛,离它最远的奶牛的距离是多少。所以首先我们枚举一头奶牛,然后对于这头奶牛求一个最远的奶牛即可(注意:我们应该需要求出两头最远的奶牛,一头顺时针距离最远的,一头逆时针距离最远的)。
        对于枚举的第一头奶牛A,我们沿着圈找到一头离它最远的奶牛B。
                        
    
        当我们沿着顺时针方向枚举第二头奶牛C时,离C最远的奶牛就不可能是图中红色区域的奶牛了,所以我们只需将B向顺时针方向枚举,当蓝色部分的距离小于红色部分时枚举停止,因为此时蓝色部分的奶牛就不可能是离C最远的奶牛了。
        对于这种方法,我们枚举的两个指针分别绕环转了一圈,所以时间复杂度为O(n),可以过题目所给的数据范围了。
    

    参考代码:

    //Powered by Dev C++ 2018/3/10 09:43
    //Be corrected by 2018/3/10 15:30
    //CCCP:Only the dead bear is the good bear.
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll shun[100005];
    ll nai[100005];
    ll ans[100005];
    int main()
    {
        int n;
        int flag;
        ll quan = 0;
        ll maximum = 0;
    //    freopen("circle.in","r",stdin);
    //    freopen("circle.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&nai[i]);
            shun[i] = shun[i-1] + nai[i];
            quan += nai[i];
        }
        flag = 1;
        for(int i=1;i<=n;i++)
        {
            for(int j=flag-1;j<=n;j++)
            {
                if( min(shun[j+1] - shun[i],quan - (shun[j+1] - shun[i]) ) < min( shun[j] - shun[i],quan - (shun[j] - shun[i]) ))
                {
                    flag = j;
                    ans[i] = min( shun[j] - shun[i],quan - (shun[j] - shun[i]) );
                    break;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            maximum = max(maximum,ans[i]);
        }
        printf("%lld",maximum);
        return 0;
    }
  • 相关阅读:
    使用httperrequest,模拟发送及接收Json请求
    VI/VIM 常用命令
    Robot Framework开发系统关键字详细
    Python logging模块使用记录
    反编译app方法
    python+appium使用记录
    查看apk包及Activity名方法
    Robot Framework使用技巧
    git 常用使用及问题记录
    多个git账户生成多份rsa秘钥实现多个账户同时使用配置
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/8542874.html
Copyright © 2011-2022 走看看