计蒜客 Entertainment Box

博客介绍了计蒜客的一道竞赛题目,主要涉及贪心算法和模拟方法。作者首先按最短时间从大到小排序任务,再按右端点从小到大排序,通过模拟判断任务执行可行性。由于数据规模限制,使用了分块策略优化模拟过程,以解决时间复杂度和内存限制问题。
摘要由CSDN通过智能技术生成

链接

https://nanti.jisuanke.com/t/28880

题解

当时比赛的时候写了个随机化暴力用来对拍QwQ
这题就是贪心,先按照做短点从大到小排序,再按照右端点从小到大排序,然后进行模拟就好了
问题在于如何模拟?
最暴力的方式就是开一个数组,涵盖每一个时间点,每次选择了新任务就把对应的所有时间点上的计数器+1,查看一个任务能否被执行,就扫描这段区间,看看最大值是不是等于 k k ,如果等于k说明此任务无法执行
首先时间不允许,其次 x,y109 x , y ≤ 10 9 ,这么大的数组也开不下,那就离散啊,然后再用分块或者线段树不就好了,为了图方便,我写的分块

代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#define lowbit(x) (x&-x)
#define maxn 200010
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
struct video
{
    int x, y;
    bool operator<(video a){return x==a.x?y<a.y:x>a.x;}
}v[maxn];
int now, ans, n, k, list[maxn], cnt[maxn], block[maxn], bmax[maxn], tag[maxn];
int read(int x=0)
{
    char c, f=1;
    for(c=getchar();!isdigit(c) and c^-1;c=getchar())if(f=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
    return f*x;
}
int ls(int x)
{
    return lower_bound(list+1,list+*list+1,x)-list;
}
void init()
{
    int i, x, y, size, t=0;
    n=read(), k=read();
    for(i=1;i<=n;i++)v[i].x=read(), v[i].y=read()-1, list[++*list]=v[i].x, list[++*list]=v[i].y;
    sort(v+1,v+n+1);
    sort(list+1,list+*list+1);
    for(i=1;i<=*list;i++)if(list[i]!=list[i-1] or i==1)list[++t]=list[i];
    *list=t;
    for(i=1;i<=n;i++)v[i].x=ls(v[i].x), v[i].y=ls(v[i].y);
    size=sqrt(*list);
    for(i=1;i<=*list;i++)block[i]=i/size;
}
void segadd(int a, int b)
{
    int i;
    for(i=block[a]+1;i<block[b];i++)tag[i]++;
    for(i=a;block[i]==block[a] and i<=b;i++)cnt[i]++, bmax[block[a]]=max(bmax[block[a]],cnt[i]);
    if(block[a]^block[b])for(i=b;block[i]==block[b] and i>=a;i--)cnt[i]++, bmax[block[b]]=max(bmax[block[b]],cnt[i]);
}
int segmax(int a, int b)
{
    int i, t=-1;
    for(i=block[a]+1;i<block[b];i++)t=max(t,tag[i]+bmax[i]);
    for(i=a;block[i]==block[a] and i<=b;i++)t=max(t,tag[block[a]]+cnt[i]);
    if(block[a]^block[b])for(i=b;block[i]==block[b] and i>=a;i--)t=max(t,tag[block[b]]+cnt[i]);
    return t;
}
void solve()
{
    int i;
    for(i=1;i<=n;i++)
    {
        if(segmax(v[i].x,v[i].y)<k)
        {
            segadd(v[i].x,v[i].y);
            ans++;
        }
    }
}
int main()
{
    init();
    solve();
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值