1. 程式人生 > >AtCoder Grand Contest 015 E - Mr.Aoki Incubator

AtCoder Grand Contest 015 E - Mr.Aoki Incubator

題目傳送門:https://agc015.contest.atcoder.jp/tasks/agc015_e

題目大意:

數軸上有\(N\)個點,每個點初始時在位置\(X_i\),以\(V_i\)的速度向數軸正方向前進

初始時刻,你可以選擇一些點為其染色,之後的行走過程中,染色的點會將其碰到的所有點都染上色,之後被染上色的點亦是如此

在所有\(2^N\)種初始染色方案中,問有多少種初始染色方案,能使得最終所有的點都被染色?答案對\(10^9+7\)取模

我們考慮按速度排序,對於每個點\(i\),我們找到最左邊的\(L\)滿足\(x_L\geqslant x_i\),找到最右邊的\(R\)滿足\(x_R\leqslant x_i\)

,那麼\(i\)被染色後,\([L,R]\)都會被染色,而且我們可以得知,染色的區間不會互相包含

這樣問題就轉變為了由一堆區間覆蓋線段的方案數,我們用單調佇列優化DP即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=2e5,p=1e9+7;
struct S1{
    int x,v;
    void rd(){x=read(),v=read();}
    bool operator <(const S1 &tis)const{return v<tis.v;}
}A[N+10];
struct S2{
    int l,r;
    void insert(int _l,int _r){l=_l,r=_r;}
    bool operator <(const S2 &tis)const{return r!=tis.r?r<tis.r:l<tis.l;}
}v[N+10];
int stack[N+10],top;
int s[N+10],f[N+10];
int main(){
    int n=read();
    for (int i=1;i<=n;i++)  A[i].rd();
    sort(A+1,A+1+n);
    for (int i=1;i<=n;i++){
        if (!top||A[i].x>A[stack[top]].x)   stack[++top]=i;
        int l=1,r=top;
        while (l<=r){
            int mid=(l+r)>>1;
            if (A[i].x<=A[stack[mid]].x)    r=mid-1;
            else    l=mid+1;
        }
        v[i].l=stack[l];
    }
    top=0;
    for (int i=n;i>=1;i--){
        if (!top||A[i].x<A[stack[top]].x)   stack[++top]=i;
        int l=1,r=top;
        while (l<=r){
            int mid=(l+r)>>1;
            if (A[stack[mid]].x<=A[i].x)    r=mid-1;
            else    l=mid+1;
        }
        v[i].r=stack[l];
    }
    sort(v+1,v+1+n);
    int now=1,Ans=0;
    for (int i=1;i<=n;i++){
        while (v[now].r<v[i].l-1)   now++;
        f[i]=(s[i-1]-s[now-1]+p)%p;
        if (v[i].l==1)  f[i]++;
        if (v[i].r==n)  Ans=(Ans+f[i])%p;
        s[i]=(s[i-1]+f[i])%p;
    }
    printf("%d\n",Ans);
    return 0;
}