1. 程式人生 > >AGC 015 E - Mr.Aoki Incubator

AGC 015 E - Mr.Aoki Incubator

lin == 染色 pan 從大到小 get 同時 中一 ring

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; }

AGC 015 E - Mr.Aoki Incubator