• AtCoder Regular Contest 101 F


    题目链接:atcoder

    考虑所有的洞将数轴划分成了若干个区间,则对每个机器人无论他怎么移动都不可能出这个区间,所以每个机器人至多只可能掉入两个洞中

    对于最左边和最右边没有洞的机器人,显然他们的掉洞方案唯一,于是我们不去考虑它,对于剩下的机器人,我们用一个二元组((l_i,r_i))表示它到离它最近的左/右边的洞的距离,很明显一个机器人掉入哪个洞只与操作序列达到的最左边/右边的位置有关。

    将所有的二元组放在一个平面上,用它们来标记一些点,操作序列的历史达到的最左边/右边的位置可以用一条只会向上和向右的折线表示。在这条折线下方的点将会落入右边的洞中,在折线上方的点将会落入左边的洞中。

    注意到只有当折线的拐角在一个被标记的点的上下发生拐弯时才会引起最终方案的变化。于是我们可以记(f_i)表示折线经过的最后一个点为(i),且最后折线向右走的方案数,由于上一个拐点只会在(i)的左下方,所以不难得到转移方程

    [f_i=1+sum_{x_j<x_i,y_j<y_i} f_j ]

    这个形式比较经典,使用树状数组维护(f)即可,注意第二维应该按照降序排序避免具有相同的(x)和较小的(y)的位置会对当前的值产生转移

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    typedef pair<int,int> pii;
    const int N=10000;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 1000000007
    #define eps 1e-8
    int n,m,tot=0,val[100100],rob[100100],hol[100100],tot1=0;
    ll f[100100];
    pii p[100100];
    
    struct fenwick_tree{
    	int a[100100];
    	
    	void modify(int x,int p)
    	{
    		for (int i=p;i<=tot;i+=lowbit(i)) a[i]=(a[i]+x)%maxd;
    	}
    	
    	int query(int p)
    	{
    		int ans=0;
    		for (int i=p;i;i-=lowbit(i)) ans=(ans+a[i])%maxd;
    		return ans;
    	}
    }tr;
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    bool cmp(pii p,pii q) {return ((p.fir<q.fir) || ((p.fir==q.fir) && (p.sec>q.sec)));}
    
    int main()
    {
    	n=read();m=read();
    	rep(i,1,n) rob[i]=read();
    	rep(i,1,m) hol[i]=read();
    	rep(i,1,n)
    	{
    		if ((rob[i]<=hol[1]) || (rob[i]>=hol[m])) continue;
    		int pos=lower_bound(hol+1,hol+1+m,rob[i])-hol;
    		if (hol[pos]==rob[i]) continue;
    		p[++tot1]=mp(rob[i]-hol[pos-1],hol[pos]-rob[i]);
    		val[++tot]=hol[pos]-rob[i];
    	}
    	//rep(i,1,n) cout << p[i].fir << " " << p[i].sec << endl;
    	sort(val+1,val+1+tot);
    	tot=unique(val+1,val+1+tot)-val-1;
    	rep(i,1,tot1) p[i].sec=lower_bound(val+1,val+1+tot,p[i].sec)-val;
    	sort(p+1,p+1+tot1,cmp);
    	tot1=unique(p+1,p+1+tot1)-p-1;
    	//cout << endl;
    	//rep(i,1,tot1) cout << p[i].fir << " " << p[i].sec << endl;
    	rep(i,1,tot1)
    	{
    		f[i]=tr.query(p[i].sec-1)+1;
    		tr.modify(f[i],p[i].sec);
    	}
    	//rep(i,1,tot1) cout << f[i] << " ";cout << endl;
    	ll ans=1;
    	rep(i,1,tot1) ans=(ans+f[i])%maxd;
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    ajax请求地址后加随机数防止浏览器缓存
    全新跨平台版本.NET敏捷开发框架-RDIFramework.NET5.0震撼发布
    一网打尽,一文讲通虚拟机VirtualBox及Linux使用
    解放双手,markdown文章神器,Typora+PicGo+七牛云图床实现自动上传图片
    VS2019 创建C++动态库dll----C#调用
    AOP面向切面的编程使用Interceptor内置的容器进行属性注入
    使用IOC内置的容器进行属性注入
    对于2021年整体预判
    亲子教育的六个阶段
    Win10 损坏硬盘命令
  • 原文地址:https://www.cnblogs.com/encodetalker/p/11618875.html
Copyright © 2020-2023  润新知