zoukankan      html  css  js  c++  java
  • CodeForces 1260D(二分+贪心+差分)

    题意

    https://vjudge.net/problem/CodeForces-1260D

    有m个士兵,t秒,你要带尽可能多的士兵从0去n+1,且他们不能被杀死。路上有一些陷阱,陷阱d[i]会杀死能力比它小的士兵,陷阱位置在l[i],当你走到r[i]时可以拆除它。每次你可以向左或者向右移动。自己不会被陷阱杀死,可以先去把陷阱拆除再回来带兵。

    思路

    首先,贪心的选最强的一些士兵,即对士兵按能力从大到小排序,然后二分选的士兵数量x,如果花的时间小于等于t,那么就可以满足。

    然后,考虑如何check,假设要带能力排前x的士兵,那么所有陷阱中大于第x个士兵的能力的都要被拆除,何时去拆呢?贪心的想肯定是先顺着走一遍把要拆的陷阱都拆了,然后一路返回再带士兵即可,而不是拆一个回来一次。

    如何O(n)时间直到哪些点必须得走呢?差分,对陷阱位置cha[l[i]] +1,对拆除位置cha[r[i]+1] -1,因为这一段路必须要走,我们再求一遍前缀和,因为差分序列的前缀和即为修改后的序列,判断每个位置是否大于0,如果大于0,则表示这个点要走。最后再加上最后带士兵要从0走到n+1的时间,判断是否小于等于t即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define ll long long
    const int N=200005;
    const int mod=1e9+7;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    #define lowbit(x) (x&(-x))
    int a[N],l[N],r[N],d[N],cha[N];
    int m,n,k,t;
    bool check(int x)
    {
        if(!x) return true;
        for(int i=0;i<=n+1;i++)
            cha[i]=0;
        int g=a[x];
        for(int i=1;i<=k;i++)
        {
            if(d[i]>g)
            {
                cha[l[i]]++,cha[r[i]+1]--;
            }
        }
        int res=0;
        for(int i=1;i<=n+1;i++)
        {
            cha[i]+=cha[i-1];
            if(cha[i]>0)
                res++;
        }
        return res*2+n+1<=t;
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        cin>>m>>n>>k>>t;
        for(int i=1; i<=m; i++)
            cin>>a[i];
        sort(a+1,a+1+m,greater<int>());
        for(int i=1;i<=k;i++)
            cin>>l[i]>>r[i]>>d[i];
        int L=0,R=m,M,ans=0;
        while(L<=R)
        {
            M=(L+R)>>1;
            if(check(M))
            {
                ans=M;
                L=M+1;
            }
            else
                R=M-1;
        }
        cout<<ans<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    我的浏览器收藏夹分类
    我的浏览器收藏夹分类
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
  • 原文地址:https://www.cnblogs.com/mcq1999/p/11957795.html
Copyright © 2011-2022 走看看