AGC 015 E

E - Mr.Aoki Incubator

链接

题意:

  数轴上有N个黑点,每个点都有一个方向向右的正速度v。当两个点在同一个位置上重合时,若其中一个是红色,另一个也变成红色。保证没有相同速度或初始坐标。现问你有多少方法染红一些点,使得无穷久后所有点都被染红。 N≤200000

分析:

   首先按照速度v从大到小排序,对于一个点,它左边的点中,坐标x第一个比它的坐标小的,设为L;右边的点中,坐标最后一个比它的坐标大的,设为R。

  那么如果这个点被染色,R-L+1区间的点都将被染色,预处理出每个点对应的区间。问题变成选一些区间,覆盖1到n的问题,dp一下。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005, mod = 1e9 + 7;
int F[N], sum[N], mn[N], mx[N];
struct Edge{ int v, l, r, x; } A[N];
bool cmp1(const Edge &A,const Edge &B) { return A.v > B.v; }
bool cmp2(const Edge &A,const Edge &B) { return A.l == B.l ? A.r < B.r : A.l < B.l; } // 左端点相同时的排序!!! 

int main() {
    int n = read();
    for (int i = 1; i <= n; ++i) 
        A[i].x = read(), A[i].v = read();
    sort(A + 1, A + n + 1, cmp1);
        
    mn[1] = A[1].x;
    for (int i = 2; i <= n; ++i) mn[i] = min(mn[i - 1], A[i].x);
    for (int i = 1; i <= n; ++i) {
        int l = 1, r = i - 1, p = i;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (mn[mid] < A[i].x) p = mid, r = mid - 1;
            else l = mid + 1;
        }
        A[i].l = p;
    }
    mx[n] = A[n].x;
    for (int i = n - 1; i >= 1; --i) mx[i] = max(mx[i + 1], A[i].x);
    for (int i = n; i >= 1; --i) {
        int l = i + 1, r = n, p = i;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (mx[mid] > A[i].x) p = mid, l = mid + 1;
            else r = mid - 1;
        }
        A[i].r = p;
    }
    sort(A + 1, A + n + 1, cmp2);
    int p = 1, Ans = 0;
    for (int i = 1; i <= n; ++i) {
        while (A[p].r < A[i].l - 1) 
            p ++;
        F[i] = (sum[i - 1] - sum[p - 1] + mod) % mod;
        if (A[i].l == 1) F[i] = (F[i] + 1) % mod;
        sum[i] = (sum[i - 1] + F[i]) % mod;
        if (A[i].r == n) Ans = (Ans + F[i]) % mod;
    }
    cout << Ans;
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10337610.html