• ARC101F Robots and Exits


    ARC101F Robots and Exits

    题意简述

    在数轴上有(n)个小球和(m)个洞。每次操作你可以将所有小球整体往左一格或整体往右一格,当落入洞中后,就不再会移动。当所有小球都掉进洞中是游戏结束。两种方案被认为不同当且仅当存在一个小球掉进了不同的洞中。

    问总方案数。

    (n,mle100000)

    解题报告

    性质一:一个小球只会掉进最靠近它的左右两边的洞中。

    性质二:一个操作是有效的(即可能有小球落入洞中),当且仅当它改变了向左移动的最大值或者向 右移动的最大值。

    性质三:对于一个小球,它的状态只取决于它先掉入哪个洞中,而这又取决于它向左移动的最大值和 向右移动的最大值哪个先到达对应的数值。

    于是,我们以向左移动的最大值为(x)轴,向右移动的最大值为(y)轴,建立平面直角坐标系。

    性质二说明:每次只能向上或向右走,所有的操作最终形成一条路径。

    根据性质三,不妨设一个小球到它左边的距离为(a),到右边的距离为(b),那么我们就在坐标系中加入一个((a,b))的点,那么该点落入哪个洞中取决于操作形成的路径与以原点为左下角,((a,b))为右上角的矩形的两边相交。

    不难发现,所有在这条路径上方的点都落入左边的洞中,其他落入右边的洞中。

    也就是说,用一条只能向上或者向右的路径将平面上的点划分为两个集合的本质不同方案数。

    因为只与划分的集合有关,所以我们不妨让路径贴着点走。

    (dp_i)表示最后一次经过的点为(i)的方案数,则有

    [dp_i=1+sum_{x_j<x_i,y_j<y_i}dp_j ]

    用扫描线+树状数组维护即可

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int sz=2e5+7;
    const int mod=1e9+7;
    int n,m;
    int ans;
    int t,len;
    int f[sz];
    int dp[sz];
    int d[sz];
    int a[sz],b[sz];
    void upd(int &x,int y){
    	x=x+y>=mod?x+y-mod:x+y;
    }
    void add(int x,int sum){
    	while(x<=len){
    		upd(f[x],sum);
    		x+=x&-x;
    	}
    }
    int query(int x){
    	int ret=0;
    	while(x){
    		upd(ret,f[x]);
    		x-=x&-x;
    	}
    	return ret;
    }
    struct node{
    	int x,y;
    	const bool operator <(const node& p)const{
    		if(x!=p.x) return x<p.x;
    		else return y>p.y;
    	}
    }c[sz];
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    	int now=1;
    	b[m+1]=INT_MAX;
    	for(int i=1;i<=n;i++){
    		if(now==1&&a[i]<=b[now]) continue;
    		while(a[i]>=b[now+1]) now++;
    		if(now==m) break;
    		c[++t]=(node){a[i]-b[now],b[now+1]-a[i]};
    		d[++len]=a[i]-b[now],d[++len]=b[now+1]-a[i];
    	}
    	sort(d+1,d+len+1);
    	len=unique(d+1,d+len+1)-d-1;
    	for(int i=1;i<=t;i++){
    		c[i].x=lower_bound(d+1,d+len+1,c[i].x)-d;
    		c[i].y=lower_bound(d+1,d+len+1,c[i].y)-d;
    	}
    	sort(c+1,c+t+1);
    	for(int i=1;i<=t;i++){
    		if(c[i].x==c[i-1].x&&c[i].y==c[i-1].y) continue;
    		dp[i]=(1+query(c[i].y-1))%mod;
    		upd(ans,dp[i]);
    		add(c[i].y,dp[i]);
    	}
    	upd(ans,1);
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    CMS初步认识
    Java编程之Map中分拣思想。
    html页面中event的常见应用
    Html页面Dom对象之Event
    mysql 之mvcc多版本控制
    关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
    除了写代码,程序员还能做哪些副业呢?
    MySQL表类型MyISAM/InnoDB的区别(解决事务不回滚的问题)(转)
    MySQL的innoDB锁机制以及死锁处理
    Kafka、RabbitMQ、RocketMQ消息中间件的对比 —— 消息发送性能-转自阿里中间件
  • 原文地址:https://www.cnblogs.com/river-flows-in-you/p/12186102.html
Copyright © 2020-2023  润新知