AT2383 [AGC015E] Mr.Aoki Incubator 题解

ATcoder
Luogu

Description.

数轴上有很多点 \((x,v)\) 表示初始在 \(x\),以 \(v\) 运动。
你可以给若干个点染色,染色点与其他点相遇后可以让未染色点带上颜色,且可以继续染色。
问有多少种初始染色状态,使得最后所有点都被染色了。

保证 \(x\) 两两不同、\(v\) 两两不同。

Solution.

\(v\) 排序。

对于每个点 \(x\),考虑我们如果染了 \(x\) 会有那些点被染
分类讨论:

  • \(v_i\le v_x\),找到一个 \(i,x_i>x_x\),那它肯定会被染,且它后面的所有点都会被染
    • 证明1:它后面的点都会被染色
      • 如果它后面的点的 \(x_j>x_x\),则它会被 \(x\) 染色
      • 否则如果 \(x_j<x_x\),它速度比 \(x\) 小追不上 \(x\),所以 \(x\) 会先把 \(i\) 染色
        但是最后它肯定在 \(i\) 后面,所以它肯定经过过已经被染色的 \(i\),所以它肯定被染了
    • 证明2:第一个 \(i,x_i>x_j\) 前面的点都不会被染色
      证明显然,位置小速度小肯定不会被染
  • \(v_i\ge v_x\),找到一个 \(i,x_i<x_x\),那它肯定会被染,且它后面的所有点都会被染
    • 证明和上文类似,不证了

所以我们证明了一个点它能染的肯定是一个区间
然后就类似于区间覆盖的 dp 套路,右端点排序。

Coding.

点击查看代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int P=1000000007;
struct node{int x,v;}a[200005];int n,dp[200005],s[200005];
struct seg{int l,r;}b[200005];int qz[200005],hz[200005];
int main()
{
	read(n);for(int i=1;i<=n;i++) read(a[i].x,a[i].v);
	sort(a+1,a+n+1,[](node a,node b){return a.v<b.v;});
	for(int i=1;i<=n;i++) qz[i]=max(qz[i-1],a[i].x);
	hz[n+1]=P;for(int i=n;i>=1;i--) hz[i]=min(hz[i+1],a[i].x);
	for(int i=1;i<=n;i++)
	{
		int r=upper_bound(hz+1,hz+n+1,a[i].x)-hz-1;
		int l=lower_bound(qz+1,qz+n+1,a[i].x)-qz;b[i]=(seg){l,r};
	}
	//for(int i=1;i<=n;i++) printf("%d %d\n",a[i].x,a[i].v);
	//for(int i=1;i<=n;i++) printf("%d %d\n",b[i].l,b[i].r);
	sort(b+1,b+n+1,[](seg a,seg b){return a.r^b.r?a.r<b.r:a.l<b.l;});
	dp[0]=s[0]=1;int l=0;for(int i=1;i<=n;i++)
	{
		while(b[l].r<b[i].l-1) l++;
		dp[i]=(s[i-1]-s[l-1]+P)%P,s[i]=(s[i-1]+dp[i])%P;
	}
	while(b[l].r<n) l++;
	return printf("%d\n",(s[n]-s[l-1]+P)%P),0;
}
posted @ 2021-10-22 14:18  Peal_Frog  阅读(44)  评论(0编辑  收藏  举报