zoukankan      html  css  js  c++  java
  • 【CF538G】Berserk Robot(思维)

    点此看题面

    • 有一个二维平面,一个机器人从原点出发。
    • 重复执行一个长度为(m)的操作序列(有上下左右四种操作)。
    • 给出机器人(n)个时刻的坐标,求一个可能的操作序列。
    • (nle2 imes10^5,mle2 imes10^6)

    二维化一维

    第一步转化就很妙。

    考虑我们把坐标系旋转(45^circ),那么就变成了左上、左下、右上、右下四个方向。

    然后发现每次操作横纵坐标各自改变(1),且二者相互独立。

    因此我们可以把它当作两个相互独立的问题分别求解,问题一下简单了很多。

    三元组((x_i,A_i,B_i))

    (S_i)(i)次操作后位置总变化量。(其实就是前(i)次操作位置变化量的前缀和)

    假设已知(T_i)时刻坐标为(B_i)

    (A_i=T_i exttt{div} m,x_i=T_i exttt{mod} m),显然第(B_i=A_i imes S_m+S_{x_i})

    基础的移项得到(S_{x_i}=-A_i imes f_m+B_i)

    这样我们得到了若干((x_i,A_i,B_i))的三元组,可以把它们按照(x_i)排个序。同时在首尾分别加上((0,0,0))((m,-1,0))(分别代表(S_0=0)(S_m=S_m)),方便后续处理。

    然后问题就是要构造一个合法的(S)序列,满足(forall iin[1,m],|S_i-S_{i-1}|=1)

    那么其实我们只要先求出(S_m)的取值范围就可以了。

    (S_m):绝对值相关的简单数学推导

    于是我们考虑每对相邻的三元组,它们之间需要满足:

    [|S_{x_{i-1}}-S_{x_i}|le|x_{i-1}-x_i| ]

    显然后面一项正负性已知,(|x_{i-1}-x_i|=x_i-x_{i-1})

    而对于前一项,我们代入(S_{x_i})的值得到:

    [|(A_i-A_{i-1}) imes S_m+(B_{i-1}-B_i)|le x_i-x_{i-1} ]

    数学老师告诉我们,这个式子恒等于:

    [x_{i-1}-x_ile (A_i-A_{i-1}) imes S_m+(B_{i-1}-B_i)le x_i-x_{i-1} ]

    移个项:

    [(x_{i-1}-x_i)-(B_{i-1}-B_i)le (A_i-A_{i-1}) imes S_mle (x_i-x_{i-1})-(B_{i-1}-B_i) ]

    然后就是根据(A_i-A_{i-1})的正负性分类讨论一下,把这个系数除掉,就可以得到(S_m)的一个取值区间。

    对所有取值区间求个交集就是(S_m)最终的取值范围了。

    构造合法序列

    对于两个相邻的三元组,设它们之间有(a)(1),那么就有(x_i-x_{i-1}-a)(-1),所以:

    [a-(x_i-x_{i-1}-a)=S_i-S_{i-1} ]

    简单移项化简得到:

    [a=frac{(S_i-S_{i-1})+(x_i-x_{i-1})}2 ]

    那么我们直接把它们之间前(a)个位置填成(1),后面填成(-1)即可。

    显然(x)不能为小数,因此要注意,尽管理论上(S_m)可以在取值范围内任取,但它的奇偶性可能影响到这个式子中分母的奇偶性,所以我们要把最小值(L)(L+1)都作为(S_m)试一遍。

    代码:(O(nlogn+m))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 200000
    #define M 2000000
    #define LL long long
    #define eps 1e-12
    using namespace std;
    int n,m,t1[M+5],t2[M+5];
    struct Data
    {
    	int x;LL A,B;I Data(CI t=0,LL a=0,LL b=0):x(t),A(a),B(b){}
    	I bool operator < (Con Data& o) Con {return x<o.x;}//根据x排序
    }s1[N+5],s2[N+5];
    LL f[N+5];I bool Try(Data* s,int* t,CI x)//f[i]指题解中的S[x[i]]
    {
    	RI i,j;LL k;for(i=1;i<=n+1;++i) f[i]=s[i].B-s[i].A*x;for(i=1;i<=m;++i) t[i]=0;//计算每个f,清空t
    	for(i=1;i<=n+1;++i) if((k=(f[i]-f[i-1])+(s[i].x-s[i-1].x))&1)//计算两个位置间有多少1
    		return 0; else for(k>>=1,j=1;j<=k;++j) t[s[i-1].x+j]=1;return 1;//是小数则非法,否则填上1
    }
    I void Work(Data* s,int* t)//求解一维答案
    {
    	#define NA() (puts("NO"),exit(0))//无解
    	RI i,j;LL L=-m,R=m;for(sort(s+1,s+n+1),s[n+1]=Data(m,-1,0),i=1;i<=n+1&&L<=R;++i)
    	{
    		if(s[i-1].A==s[i].A) {if(abs(s[i-1].B-s[i].B)>s[i].x-s[i-1].x) NA();}//A[i]-A[i-1]=0
    		else s[i-1].A<s[i].A?//A[i]-A[i-1]>0
    		(
    			L=max(L,(LL)ceil(1.0L*((s[i-1].x-s[i].x)-(s[i-1].B-s[i].B))/(s[i].A-s[i-1].A)-eps)),
    			R=min(R,(LL)floor(1.0L*((s[i].x-s[i-1].x)-(s[i-1].B-s[i].B))/(s[i].A-s[i-1].A)+eps))
    		)://A[i]-A[i-1]<0
    		(
    			L=max(L,(LL)ceil(1.0L*((s[i].x-s[i-1].x)-(s[i-1].B-s[i].B))/(s[i].A-s[i-1].A)-eps)),
    			R=min(R,(LL)floor(1.0L*((s[i-1].x-s[i].x)-(s[i-1].B-s[i].B))/(s[i].A-s[i-1].A)+eps))
    		);
    	}
    	if(L>R||(!Try(s,t,L)&&(L+1>R||!Try(s,t,L+1)))) NA();//分别尝试L和L+1
    }
    int main()
    {
    	RI i;LL t,x,y;for(scanf("%d%d",&n,&m),i=1;i<=n;++i)
    		scanf("%lld%lld%lld",&t,&x,&y),s1[i]=Data(t%m,t/m,x-y),s2[i]=Data(t%m,t/m,x+y);//坐标系转45°
    	for(Work(s1,t1),Work(s2,t2),i=1;i<=m;++i)
    		putchar(t1[i]?(t2[i]?'R':'D'):(t2[i]?'U':'L'));return 0;//把两个一维拼起来得到二维答案
    }
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 数的统计
    Java实现 蓝桥杯VIP 算法训练 和为T
    Java实现 蓝桥杯VIP 算法训练 友好数
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 暗恋
    Java实现 蓝桥杯VIP 算法训练 暗恋
    测试鼠标是否在窗口内,以及测试鼠标是否在窗口停留
    RichEdit 各个版本介绍
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF538G.html
Copyright © 2011-2022 走看看