## 前言。
本题解是 $D1$ 的题解:
这篇题解是在 $D1$ 的基础上进行编写的,所以该代码仅仅针对该题,对于另外两个加强版是无法通过的,这里注重从 $0$ 开始的由简入难的思考过程。
这个基础题的思路就是模拟,因为这个 $b$ 实在是太小了。
## 分析。
### 题意简述:
给定一个 $n$ 阶方正地图,地图上存在 $m$ 条路标,其中保证任意的路径与坐标轴平行且两两互不相交,随后 $m$ 行是路标的起始坐标 $\left(x_1,y_1\right)$ 和终点坐标 $\left(x_2,y_2\right)$。随后给出 $q$ 次询问,每次询问给出海狸的初始坐标 $\left(x_i,y_i\right)$ 和初始的走向共四种情况,其中 ```U```、```D```、```L``` 和 ```R``` 分别表示向上移动,向下移动,向左运动和向右运动,还有距离开始经过的时间。时间的限制条件为 $t_i\leq 10^{15}$ 个单位时间。输出 $q$ 行。每行应包含两个整数,海狸在每个询问中当时间为 $t_i$ 时所处的坐标。如果在 $t_i$ 时间内成功离开地图,则打印他最后访问的地图内的坐标。
### 正式的讲解:
因为有 $t_i$ 的限制条件,所以我们从中入手,显然这个数据太大了,如果对于每个询问都直接模拟会直接超时,所以我们考虑找一个简便的方法来减少每次询问的次数。首先我们需要根据这些路标把整个图建出来,然后开始模拟。有一个很显然的思路是找循环节,如果海狸进了循环,那么无论 $t_i$ 多大,都会在一个特定的范围内循环,所以直接找到循环节后找到 $t_i$ 所对应的那个坐标就行。那么此时这个循环的情况查询时间就成了 $O\left(1\right)$。这个情况在每次询问中直接预处理然后直接对循环节取余即可。
然后这样可以证明,很容易出现循环节,所以可行。剩下的直接模拟即可,时间复杂度就大大降低了。然后最后处理一下直接跑出跑出地图,就直接结束模拟即可,因为海狸已经跑出地图并留下最后的访问过的坐标了。
代码如下,仅供参考:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
int n,b,x1,x2,y_1,y2,q1,x,y;
long long t;
char way;
int disx,disy;
long long timee;
int G[1005][1005],vis[1005][1005],sum[1005][1005];
struct node{
int x,y;
}a[1005*1005];
int dx[7]={0,1,0,-1,0};
int dy[7]={0,0,1,0,-1};
map <char, int> ma;
void add(int x1,int y_1,int x2,int y2){//建图。
int dis=0;
if (x1==x2){
(y_1<y2)?dis=2:dis=4;
//处理上下移动的情况。
}
else{
(x1<x2)?dis=1:dis=3;
//处理左右移动的情况。
}
G[x2][y2]=dis;
while (x1!=x2||y_1!=y2){
G[x1][y_1]=dis;
x1+=dx[dis];
y_1+=dy[dis];
}
}
int main(){
ma['R']=1;
ma['U']=2;
ma['L']=3;
ma['D']=4;
cin>>n>>b;
for (int i=1;i<=n;i++){
cin>>x1>>y_1>>x2>>y2;
//cout<<"yep!\n";
add(x1,y_1,x2,y2);
}
cin>>q1;
for (int i=1;i<=q1;i++){
timee=0;
cin>>x>>y>>way>>t;
disx=dx[ma[way]];
disy=dy[ma[way]];//看看距离。
while(x>=0&&x<=b&&y>=0&&y<=b&&t>0){
if(G[x][y]){//如果存在路标。
disx=dx[G[x][y]];
disy=dy[G[x][y]];
}
if(G[x][y]&&vis[x][y]==i){//如果存在循环节。
/*t%=(timee-(long long)sum[x][y]);
x=a[(long long)sum[x][y]+t].x;
y=a[(long long)sum[x][y]+t].y;
break;*/
long long summ=sum[x][y];
long long xhj=timee-summ;
t%=xhj;
x=a[summ+t].x;
y=a[summ+t].y;
break;
}
sum[x][y]=timee;
a[timee].x=x;
a[timee++].y=y;
vis[x][y]=i;
t--;
x+=disx;
y+=disy;//更新新的坐标.
}
if(x<0){
x=0;
}
if(x>b){
x=b;
}
if(y<0){
y=0;
}
if(y>b){
y=b;
}//判断边界情况,是否越界,越界就记录海狸出去的那一个点。
cout<<x<<" "<<y<<"\n";
}
return 0;
}
/*
4 2
0 0 1 0
2 0 2 1
2 2 1 2
0 2 0 1
15
1 1 R 7
0 0 U 3
1 1 R 888888888888887
0 0 U 404040404040403
2 1 D 1000000000000000
2 0 R 324354768576473
2 0 L 325436475453245
2 0 U 764536452343654
2 0 D 943654765876545
1 1 U 1000000000000000
1 1 D 989898789898789
1 1 L 123456787654344
0 1 L 0
0 1 L 1
0 1 L 999999999999993
*/
## 后记。
一个很好想的思路,但是细节蛮多的。
大家如有疑问,可以在评论区提出,我会尽力解答的。