矿石

矿石

题目描述

 

众所周知,九条可怜家里有矿。

你可以把可怜家的矿场抽象成一条数轴。可怜家有nn种矿,第ii种矿可以从[li,ri]的任意位置开采得到。

这个暑假,地理老师给了可怜一个列表:可怜的暑假作业就是收集齐这些矿石。为了保证可怜的安全,可怜的爸爸选定了m个相对安全的采矿点,第ii个采矿点的坐标为ai。可怜只能选择其中一个采矿点开采她需要的矿石。

可怜是一个马虎的女孩子。暑假刚开始没多久,可怜就把老师的列表弄丢了。唯一的线索是,列表上的所有矿石都是可怜家有的:一共有2n−12n−1种可能的列表。

可怜现在想要知道,在所有的可能的任务列表中,有多少种是她能够在某一个安全的采矿点完全收集齐的。

 

n1e5


solution

考虑每一个采矿点。

记它与上一个矿点相比,少掉的矿石集合为A,多出的集合为B,相同的为C

因为矿石是一段连续的区间,所以A集合再也不会出现了。

C内部的贡献不必再算,只需计算BC间和B的贡献。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define maxn 100005
#define ll long long
#define mod 998244353
using namespace std;
int n,m,a[maxn],top,flag[maxn];
ll ans,F[maxn];
struct node{
    int id,l,r;
    bool operator<(const node &T)const{
        return T.r<r;
    };
}s[maxn],zh[maxn];
priority_queue<node>q;
bool cmpl(node a,node b){
    return a.l<b.l;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d%d",&s[i].l,&s[i].r);
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    sort(s+1,s+n+1,cmpl);
    sort(a+1,a+m+1);
    F[0]=1;for(int i=1;i<=n;i++)F[i]=(F[i-1]*2)%mod;
    for(int i=0;i<n;i++)F[i]--;
    int now=1;
    for(int i=1;i<=m;i++){
        while(!q.empty()){
            if(q.top().r<a[i])q.pop();
            else break;
        }
        int A=q.size(),B;
        for(;s[now].l<=a[i]&&now<=n;now++){
            if(s[now].r>=a[i])q.push(s[now]);
        }
        B=q.size();
        ans=ans+F[B]-F[A];ans%=mod;
    }
    ans=(ans%mod+mod)%mod;
    cout<<ans<<endl;
    return 0;
}

 

 

posted @   liankewei123456  阅读(507)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示