zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    linux下开启防火墙,允许通过的端口
    linux下限定连接ip和端口
    centos7关闭防火墙
    linux下清空文件内容的3个命令
    yum安装软件包提示Error Downloading Packages解决方法
    Zabbix 监控服务介绍
    Redis 应用
    分布式中间件MyCat 使用
    DevOps Gitlab环境部署
    MySQL Atlas 读写分离软件介绍
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15438651.html
Copyright © 2011-2022 走看看