zoukankan      html  css  js  c++  java
  • [ACM]51nod 贪心专题


    51nod一个贪心专题,大多数都是见过的套路,做题找找感觉,有些题解思路懒得写了,直接贴毕姥爷的直播题解了

    A 低买高卖

    考虑股票市场,一共有n天。对于第i天,B君知道股票的价格是每单位a[i]元在每一天,B君可以选择买入一个单位的股票,卖出一个单位的股票,或者什么都不做。
    刚开始B君有无穷多的钱,但是没有任何股票。问n天之后B君最多可以赚多少钱。(1 <= n <= 200000)(1 <= a[i] <= 10000)

    输入
    第一行一个整数n表示天数。
    接下来一行n个整数,表示每天的价钱。
    输出
    一行一个整数表示最多可以赚的钱数。
    输入样例

    9
    10 5 4 7 9 12 6 2 10
    

    输出样例

    20
    

    思路, 这道题是个很好的题目,也算是一个不错的套路贪心题, 这题很容易想到的是n^2 DP, dp[i][j]代表前i天j个股票的价钱,但是会t, 所以可以贪心来做, 我们假设每一天都在卖股票,但是不可能每一天都在卖的之前肯定要买股票后面才能卖,因此转换一下把卖出去转换为持有,把持有转换为买入, 对于当前价格B而言,只要前面有比这个价格低的价格A,那么当前情况A买入B卖出一定盈利,但是A买入B卖出不一定是最优解,所以为了有后悔药吃,就再push两个B进入优先队列,一个表示卖出,一个表示买入。每天都卖出,每次累加差值就可以了。累加很多个差分值肯定会得到最优解的。因为A买入B卖出B买入C卖出 和 A买入C卖出 效果一样
    代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    using namespace std;
    priority_queue<int> pq;
    int main()
    {
        int n, x;
        while(~scanf("%d", &n))
        {
            while (pq.size())
                pq.pop();
            int ans = 0;
            for(int i = 1; i <= n; i++)
            {
                scanf("%d", &x);
                pq.push(-x);
                ans += x + pq.top();
                pq.pop();
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    C 接水问题

    n个人一起排队接水,第i个人的重要性是a[i],需要b[i]的时间来接水。
    1 <= n <= 100000
    0 <= b[i] <= 1000
    0 <= a[i] <= 1000
    同时只能有一个人接水,正在接水的人和没有接水的人都需要等待。
    完成接水的人会立刻消失,不会继续等待。
    你可以决定所有人接水的顺序,并希望最小化所有人等待时间乘以自己的重要性a[i]的总和。
    输入
    第一行一个整数n。
    以下n行,每行两个整数a[i]和b[i]。
    输出
    一行一个整数表示答案。
    输入样例

    4
    1 4
    2 3
    3 2
    4 1
    

    输出样例

    35
    

    思路: 思路很简单,经典套路,直接比较相邻两个, 这题要注意 a与b都可能为0, 之前想着把除法转为乘法让a不为0即分子不为0就行, 但是这样是有问题的, 对于 (frac{a_1}{b_1})本应该是(>frac{0}{0})的,但是转为乘法之后他们他们就是 (0 = 0)了,排序显然会出现问题,因此要么把a = 0.b = 0的样例排除掉,要么特判相等的时候,让他返回 a1 < a2,即通过特判a来让0在前面。
    代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e5 + 5;
    typedef long long ll;
    struct node
    {
        ll a, b;
        bool operator < (const node &tmp) const
        {
            return tmp.a*b < a*tmp.b || (tmp.a*b == a*tmp.b && a < tmp.a);
        }
    }x[maxn];
    int main()
    {
        int n;
        while(~scanf("%d", &n))
        {
            for(int i = 1; i <= n; i++)
            {
                scanf("%lld%lld", &x[i].a, &x[i].b);
            }
            sort(x+1, x+1+n);
            ll pre = 0, ans = 0;
            for(int i = 1; i <= n; i++)
            {
                pre = pre + x[i].b;
                ans = ans + pre*x[i].a;
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    
    

    D做任务一

    B君和m个人一起,要完成n个任务,在这个题中,m个人会看着这B君,自己什么都不做。
    第i个任务有一个开始时间s[i]和结束时间e[i](保证s[i]<=e[i]),一个人完成两个任务的时间区间,不能有交集,但是可以首尾相连。(参考样例)
    换句话说,如果一个人依次完成了(s[1], e[1]) (s[2], e[2]) (s[3], e[3])这3个任务,那么这3个任务需要满足s[1]<=e[1]<=s[2]<=e[2]<=s[3]<=e[3]。
    同一个任务只能完成一次,并且中间不能换人。
    问B君一个人最多可以完成多少个任务。
    (单组 n <= 100000)
    (所有 n 求和 <= 200000)
    (开始时间和结束时间,都是非负整数,且在int范围内。)
    (开始时间 <= 结束时间,如果等于的话,意味着这个任务可以瞬间被做完,但是不能没有人做)
    输入
    多组数据,第一行是数据组数。
    每组数据的第一行两个整数n, m分别表示任务数,和人数。
    以下n行,每行两个整数表示任务的开始时间和结束时间。
    输出
    对于每组数据输出一个整数
    表示一个人最多可以完成多少个任务。
    输入样例

    2
    2 1
    1 3
    2 4
    2 1
    1 3
    3 5
    

    输出样例

    1
    2
    

    注意以下两个思路, 一定要记得把另一个端点按照相同的方法排序, 因此会有 s==e的情况,如果另一个端点随机排序,会错误,可以自己举例看一下。
    思路1:

    代码1:

    
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn = 1e5 + 20;
    struct node
    {
        int l, r;
        bool operator < (const node &tmp) const
        {
            if(r != tmp.r)
                return r < tmp.r;
            else
                return l < tmp.l;
        }
    }a[maxn];
    int main()
    {
        int _, n, m;
        cin >> _;
        while(_--)
        {
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= n; i++)
                scanf("%d%d", &a[i].l, &a[i].r);
            sort(a + 1, a + 1 + n);
            int ans = 0, r = 0;
            for (int i = 1; i <= n; i++)
            {
                if (a[i].l >= r) r = a[i].r, ans++;
            }
            printf("%d
    ", ans);
    
        }
        return 0;
    }
    

    思路1:

    代码2:

    
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    using namespace std;
    const int maxn = 100000 + 5;
    struct node
    {
        int l, r;
        bool operator < (const node &a) const
        {
            if(l != a.l)
                return l < a.l;
            else 
                return r < a.r;
        }
    }a[maxn];
    int main()
    {
        int t;
        cin >> t;
        while(t--)
        {
            int n, m;
            scanf("%d%d", &n,&m);
            for(int i = 1; i <= n; i++)
            {
                scanf("%d%d", &a[i].l, &a[i].r);
            }
            sort(a+1, a+1+n);
            int r = 0, ans = 0;
            for(int i = 1; i <= n; i++)
            {
                if(a[i].l >= r) r = a[i].r, ans++;
                else if(a[i].r < r) r = a[i].r;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    E做任务三

    B君和m个人一起,要完成n个任务,在这个题中,B君和m个人,什么都不做。
    第i个任务有一个开始时间s[i]和结束时间e[i](保证s[i]<=e[i]),一个人完成两个任务的时间区间,不能有交集,但是可以首尾相连。(参考样例)
    换句话说,如果一个人依次完成了(s[1], e[1]) (s[2], e[2]) (s[3], e[3])这3个任务,那么这3个任务需要满足s[1]<=e[1]<=s[2]<=e[2]<=s[3]<=e[3]。
    同一个任务只能完成一次,并且中间不能换人。
    B君和m个人,想知道要想完成这些任务,至少需要几个人?
    (单组 n <= 100000)
    (所有 n 求和 <= 200000)
    (开始时间和结束时间,都是非负整数,且在int范围内。)
    (开始时间 <= 结束时间,如果等于的话,意味着这个任务可以瞬间被做完,但是不能没有人做)
    输入
    多组数据,第一行是数据组数。
    每组数据的第一行两个整数n, m分别表示任务数,和人数。
    以下n行,每行两个整数表示任务的开始时间和结束时间。
    输出
    对于每组数据输出一个整数
    表示完成这些任务至少需要多少人。
    输入样例

    4
    2 1
    1 3
    2 4
    2 1
    1 3
    3 5
    2 1
    1 3
    2 2
    4 1
    1 2
    2 2
    2 2
    2 3
    

    输出样例

    2
    1
    2
    1
    

    思路1:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    using namespace std;
    const int maxn = 100000 + 5;
    struct node
    {
        int l, r;
        bool operator < (const node &a) const
        {
            if(l != a.l)
                return l < a.l;
            else
                return r < a.r;
        }
    }a[maxn];
    int main()
    {
        int t;
        cin >> t;
        while(t--)
        {
            priority_queue<int> pq;
            int n, m;
            scanf("%d%d", &n,&m);
            for(int i = 1; i <= n; i++)
            {
                scanf("%d%d", &a[i].l, &a[i].r);
            }
            sort(a+1, a+1+n);
            int r = 0, ans = 0;
            for(int i = 1; i <= n; i++)
            {
                if(!pq.size()) pq.push(-a[i].r), ans++;
                else
                {
                    if (a[i].l >= -pq.top())
                    {
                        pq.pop();
                    }
                    else
                    {
                        ans++;
                    }
                    pq.push(-a[i].r);
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    思路2:


    这个思路代码就先不写了, 第一个思路比较容易写也好理解

  • 相关阅读:
    AJAX---发送GET请求并传递参数
    AJAX---遵循http协议
    AJAX---onreadystatechange事件中获取相应内容和readystate状态
    AJAX---发送请求
    AJAX---简介
    AJAX---学习roadmap
    jQuery---jquery.ui实现新闻模块
    jQuery---jquery.color.js和jquery.lazyload.js的使用
    jQuery---jQuery插件
    通过JavaScript调用SOAP终结点执行实体消息
  • 原文地址:https://www.cnblogs.com/kk17/p/10099198.html
Copyright © 2011-2022 走看看