Always keep a beginner's mind, don't |

luckydrawbox

园龄:4个月粉丝:1关注:2

题解:CF1993F1 Dyn-scripted Robot (Easy Version)

Link\text{Link}

题意

在平面直角坐标系中,机器人初始位于 (0,0)(0,0),有一段长度为 nn 的仅包含 DULR\texttt{DULR} 的操作序列 ss,机器人将把此操作序列执行 kk 轮,要求机器人任意时刻的位置都必须在 (0,0)(h,w)(0,0)-(h,w) 的矩形中,若按第 ii 个操作移动会超出矩形,那么若 sis_iL/R\texttt{L/R},将 ss 中所有 L\texttt{L} 变成 R\texttt{R},所有 R\texttt{R} 变成 L\texttt{L};若 sis_iU/D\texttt{U/D} 也同理。变换后再执行第 ii 个操作,注意变换对操作序列的影响会保留到下一轮。

求机器人在移动过程中经过 (0,0)(0,0) 的次数(不包括初始状态)。

数据范围:tt 为数据组数,1t104,1n,w,h106,1kn1 \le t \le 10^4,1 \le \sum n,w,h \le 10^6,1 \le k \le n

由于神秘原因,本题解的 h,wh,w 对应原题中的 w,hw,h

分析

场上想不出 F1 的简单做法,但会了 F2,然而由于时间原因最终没有调出来。

先考虑一个简单的转化:带限制走到 (0,0)(0,0) 相当于不带限制走到 (2ah,2bw) (a,bZ)(2ah,2bw)\ (a,b\in \mathbb{Z})

简单证明一下,假设一次 U\texttt{U} 时超出了矩阵,那么 L,R\texttt{L,R} 不受影响,若不改变操作序列,则相当于把走到 (0,0)(0,0) 改为了走到 (0,2w)(0,2w)D,L,R\texttt{D,L,R} 也以此类推,所以转化成立。

于是问题要求经过 (2ah,2bw) (a,bZ)(2ah,2bw)\ (a,b\in \mathbb{Z}) 的次数,显然一轮后的位移是固定的,令其为 (X,Y) (0X<2h,0Y<2w)(X,Y)\ (0\le X< 2h,0\le Y<2w),所以我们枚举一轮中第 ii 个操作作为结尾,设第一轮中第 ii 次操作后位于 (xi,yi)(x_i,y_i),那么在第 j+1 (0jk1)j+1\ (0\le j\le k-1) 轮中机器人位于 (xi+jX,yi+jY)(x_i+jX,y_i+jY)

先将 x,yx,y 分开考虑,那么 xi+jX=2ah,yi+jY=2bwx_i+jX=2ah,y_i+jY=2bw

可以转化为同余方程 jXxi(mod2h),jYyi(mod2w)jX\equiv -x_i\pmod {2h},jY\equiv -y_i\pmod {2w},用两次 exgcd\texttt{exgcd} 分别算出两个方程的通解,再用一次 exgcd\texttt{exgcd} 合并即可。

时间复杂度 O(nlogk)O(n\log k)

代码

#include<bits/stdc++.h>
#define ll long long
#define PY puts("YES")
#define PN puts("NO")
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch))
	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=1e6+10;
int t,n,h,w;
ll k,ans; 
string s;
int fx[4]={0,0,-1,1};
int fy[4]={-1,1,0,0};
struct Node{
	int x,y;
}a[N];
Node forward(Node p,int t){
	return (Node){p.x+fx[t],p.y+fy[t]};
}
int turn(char c){
	if(c=='D')return 0;
	if(c=='U')return 1;
	if(c=='L')return 2;
	return 3;
}
long long exgcd(long long a,long long b,long long &x,long long &y){
    if(!b){
        x=1;y=0;
        return a;
    }
    long long d=exgcd(b,a%b,x,y);
    long long z=x;x=y;y=z-y*(a/b);
    return d;
}
ll solve(Node p,ll k){
	int vv=(p.x==0&&p.y==0);
	p.x=h-p.x;p.y=w-p.y;
	ll hx0,hy0,hd,hB;
	hd=exgcd(a[n].x,h,hx0,hy0);
	if(p.x%hd)return vv;
	hB=h/hd;
	hx0*=p.x/hd;hx0=(hx0%hB+hB)%hB;
	ll wx0,wy0,wd,wB;
	wd=exgcd(a[n].y,w,wx0,wy0);
	if(p.y%wd)return vv;
	wB=w/wd;
	wx0*=p.y/wd;wx0=(wx0%wB+wB)%wB;
	ll x0,y0,d,B,xy;
	if(wx0<hx0)swap(wx0,hx0),swap(hB,wB);
	xy=(wx0-hx0)%wB;
	d=exgcd(hB,wB,x0,y0);
	if(xy%d)return vv;
	B=wB/d;
	x0*=xy/d;x0=(x0%B+B)%B;
	ll u=k-hx0;if(u<0)return vv;
	u=(u/hB-x0);if(u<0)return vv;
	u/=B;
	return u+vv+(x0*hB+hx0!=0&&x0*hB+hx0<=k);
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	t=read();
	while(t--){
		cin>>n>>k>>h>>w>>s;
		a[0]=(Node){0,0};
		h*=2;w*=2;
		for(int i=1;i<=n;i++){
			a[i]=forward(a[i-1],turn(s[i-1]));
			a[i].x=(a[i].x%h+h)%h;
			a[i].y=(a[i].y%w+w)%w;
		}
		ans=0;
		for(int i=1;i<=n;i++)
			ans+=solve(a[i],k-1);
		cout<<ans<<endl;
	}
	return 0;
}

本文作者:luckydrawbox

本文链接:https://www.cnblogs.com/luckydrawbox/p/18526430

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   luckydrawbox  阅读(4)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起