众所周知,九条可怜家里有矿
你可以把可怜家的矿场抽象成一条数轴,可怜家有n种矿,第i种矿可以从[li,ri] 中的任意位置开采得到
这个暑假,地理老师给了 可怜一个列表:她的暑假作业就是收集齐这些矿石
为了保证可怜的安全,可怜的爸爸选定了m个相对安全的采矿点,第i个采矿点的坐标为ai
可怜只能选择其中一个采矿点开采她需要的矿石
可怜是一个马虎的女孩子。暑假刚开始没多久,可怜就把老师的列表弄丢了
唯一的线索是,列表上的所有矿石都是可怜家有的,则一共有2^n-1种可能的列表
现在想要知道,在所有的可能的任务列表中,有多少种是她能够在某一个安全的采矿点收集齐的
\[\text{tqr乱搞的图片与此题无强关联性……}\]
今天的题过于水了,由于矿脉成连续分布
所以只需要统计这个采矿点和上个采矿点的差异
即,多了哪些矿,少了哪些矿。就好了
代码:
#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
using namespace std;
int n,m,loc[100005];
ll ans=0,two[100005];
struct Stone
{
int l,r;
bool operator < (const Stone &a) const
{
return a.r<r;
};
}a[100005];
bool cmp(Stone a,Stone b) {return a.l==b.l?a.r<b.r:a.l<b.l;}
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
priority_queue<Stone> q;
inline void init()
{
two[0]=1;
for(register int i=1;i<=n;++i) two[i]=(two[i-1]<<1)%mod;
for(register int i=0;i<n;++i) two[i]--;
sort(a+1,a+n+1,cmp);
sort(loc+1,loc+m+1);
}
int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
read(n);read(m);
for(register int i=1;i<=n;++i)
{
read(a[i].l);
read(a[i].r);
}
for(register int j=1;j<=m;++j) read(loc[j]);
init();
int now=1;
for(register int i=1;i<=m;++i)
{
while(!q.empty())
{
if(q.top().r<loc[i]) q.pop();
else break;
}
int presiz=q.size();
while(a[now].l<=loc[i])
{
if(now>n) break;
if(a[now].r>=loc[i]) q.push(a[now]);
now++;
}
int nowsiz=q.size();
ans=(ans+two[nowsiz]-two[presiz])%mod;
}
ans=(ans+mod)%mod;
printf("%lld\n",ans);
return 0;
}