CF538GBerserk Robot(思维)
Posted chenxiaoran666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF538GBerserk 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):绝对值相关的简单数学推导
于是我们考虑每对相邻的三元组,它们之间需要满足:
显然后面一项正负性已知,(|x_{i-1}-x_i|=x_i-x_{i-1})。
而对于前一项,我们代入(S_{x_i})的值得到:
数学老师告诉我们,这个式子恒等于:
移个项:
然后就是根据(A_i-A_{i-1})的正负性分类讨论一下,把这个系数除掉,就可以得到(S_m)的一个取值区间。
对所有取值区间求个交集就是(S_m)最终的取值范围了。
构造合法序列
对于两个相邻的三元组,设它们之间有(a)个(1),那么就有(x_i-x_{i-1}-a)个(-1),所以:
简单移项化简得到:
那么我们直接把它们之间前(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;//把两个一维拼起来得到二维答案
}
以上是关于CF538GBerserk Robot(思维)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #538 (Div. 2) (CF1114)