题解:AT_abc219_f [ABC219F] Cleaning Robot
__vector__ · · 题解
模拟赛考了这题,场上因为细节写挂,差点通过这题,特此记录。
首先,观察一下最终走过的点的坐标形式都是什么。
令前
那么,对于所有
- 存在一个非负整数
k \lt K ,以及(sx,sy) \in S ,使得(sx+k\cdot dx,sy+k\cdot dy) = (x,y) - 存在一个非负整数
k \le K ,使得(x,y) = (k\cdot dx,k\cdot dy)
换个理解方式,就是对于任意
首先,由于我不喜欢比较重要的地方出现负数,所以,如果 U 换成 D,L 换成 R)。
答案一定不会改变,因为是对称的,然后,就能保证
然后,考虑按照顺序遍历
此时,就需要分析怎么计算当前的元素产生的位置里面,有哪些是和之前遍历过的元素产生的位置重复了。
回想一下判定条件。
假设当前扫描到了
- 首先,需要满足
\frac{x_1-x_2}{dx} = \frac{y_1-y_2}{dy} 。
本条件的原因是,加上的dx,dy 分别乘上的倍数都是相等的。
本条件可以转化为x_1\cdot dy - y_1 \cdot dx = x_2 \cdot dy - dx \cdot y_2 ,这样等式两边分别都只包含来自同一个元素的值,以及差不多相当于常量的dx,dy 。 - 其次,需要满足
x_1 \equiv x_2 \pmod {dx},y_1 \equiv y_2 \pmod {dy} 。
如果不满足这个,那么当然是不能相等的,因为不能有小数。 - 然后,需要满足
|\frac{x_1-x_2}{d_x}| \lt k + [(x_2,y_2) = (0,0)] 。
综上,定义一个
考虑开一个 map,存储每一种类别属性的所有元素。
回到原来问题,此时可以发现,和
当前元素产生的新位置的形式为
这些邻居元素,实际的影响就是使得一段前缀或者后缀的
map 里面开两个 set,分奇偶分别存储所有的位置就可以了。
对于
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(auto i=(a);i<=(b);i++)
#define REP(i,a,b) for(auto i=(a);i>=(b);i--)
#define FORK(i,a,b,k) for(auto i=(a);i<=(b);i+=(k))
#define REPK(i,a,b,k) for(auto i=(a);i>=(b);i-=(k))
#define pb push_back
#define mkpr make_pair
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
template<class T>
void ckmx(T& a,T b){
a=max(a,b);
}
template<class T>
void ckmn(T& a,T b){
a=min(a,b);
}
template<class T>
T gcd(T a,T b){
return !b?a:gcd(b,a%b);
}
template<class T>
T lcm(T a,T b){
return a/gcd(a,b)*b;
}
#define gc getchar()
#define eb emplace_back
#define pc putchar
#define ep empty()
#define fi first
#define se second
#define pln pc('\n');
#define islower(ch) (ch>='a'&&ch<='z')
#define isupper(ch) (ch>='A'&&ch<='Z')
#define isalpha(ch) (islower(ch)||isupper(ch))
template<class T>
void wrint(T x){
if(x<0){
x=-x;
pc('-');
}
if(x>=10){
wrint(x/10);
}
pc(x%10^48);
}
template<class T>
void wrintln(T x){
wrint(x);
pln
}
template<class T>
void read(T& x){
x=0;
int f=1;
char ch=gc;
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=gc;
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=gc;
}
x*=f;
}
void ioopti(){
ios::sync_with_stdio(0);
cin.tie(0);
}
#define int ll
#define pii pll
#define vi vector<ll>
const int maxn=2e5+5;
int n;
char s[maxn];
ll k;
struct REM{
ll mx=-2e18,my=-2e18,cha=-2e18;
void init(){
mx=-2e18,my=-2e18,cha=-2e18;
}
bool operator<(const REM& b)const{
if(mx!=b.mx)return mx<b.mx;
if(my!=b.my)return my<b.my;
return cha<b.cha;
}
};
map<REM,set<int> > oklistx,oklisty;
vector<pii> rem;
ll dx,dy;
void solve(int id_of_test){
scanf("%s",s+1);
n=strlen(s+1);
read(k);
{
pii cur=mkpr(0,0);
FOR(i,1,n){
rem.eb(cur);
// printf("%d %d\n",cur.fi,cur.se);
if(s[i]=='L')cur.fi--;
if(s[i]=='R')cur.fi++;
if(s[i]=='U')cur.se++;
if(s[i]=='D')cur.se--;
}
dx=cur.fi,dy=cur.se;
}
{
if(dx<0){
FOR(i,1,n){
if(s[i]=='L')s[i]='R';
else if(s[i]=='R')s[i]='L';
}
}
if(dy<0){
FOR(i,1,n){
if(s[i]=='U')s[i]='D';
else if(s[i]=='D')s[i]='U';
}
}
rem.clear();
pii cur=mkpr(0,0);
FOR(i,1,n){
rem.eb(cur);
// printf("%d %d\n",cur.fi,cur.se);
if(s[i]=='L')cur.fi--;
if(s[i]=='R')cur.fi++;
if(s[i]=='U')cur.se++;
if(s[i]=='D')cur.se--;
}
dx=cur.fi,dy=cur.se;
}
// printf("dx %d dy %d\n",dx,dy);
if(!dx&&!dy){
auto tmp=rem;
sort(tmp.begin(),tmp.end());
printf("%lld\n",ll(unique(tmp.begin(),tmp.end())-tmp.begin()));
return;
}
{
int cnt=0;
ll ans=0;
for(auto [x,y]:rem){
cnt++;
REM tmp;
tmp.init();
if(dx)tmp.mx=(x%dx+dx)%dx;
else tmp.mx=x;
if(dy)tmp.my=(y%dy+dy)%dy;
else tmp.my=y;
if(dx&&dy){
tmp.cha=x*dy-y*dx;
}
ll l=0,r=k-1;// 至少增长 0 次,最多增长 k-1 次。
if(cnt==1){
r++;
}
{
{// 处理 x 方向限制
auto& okl=oklistx[tmp];
auto pos=okl.lower_bound(x);
if(pos!=okl.end()){
// 第一个大于等于 x 的位置。
if(dx>0){
// 当前主动向 x 更大延申
ckmn(r,(*pos-x)/dx-1);
}
}
if(pos!=okl.begin()){
pos--;
// x 更小的位置
if(dx>0){
// 需要考虑更小位置向当前延申
ckmx(l,((*pos+(k-1)*dx)-x)/dx+1);
}
}
}
#define x y
#define dx dy
#define oklistx oklisty
{// 处理 x 方向限制
auto& okl=oklistx[tmp];
auto pos=okl.lower_bound(x);
if(pos!=okl.end()){
// 第一个大于等于 x 的位置。
if(dx>0){
// 当前主动向 x 更大延申
ckmn(r,(*pos-x)/dx-1);
}
}
if(pos!=okl.begin()){
pos--;
// x 更小的位置
if(dx>0){
// 需要考虑更小位置向当前延申
ckmx(l,((*pos+(k-1)*dx)-x)/dx+1);
}
}
}
#undef x
#undef dx
#undef oklistx
// printf("[%lld %lld]\n",l,r);
ans+=max(0ll,r-l+1);
}
{
REM tmp;
tmp.init();
if(dx)tmp.mx=(x%dx+dx)%dx;
else tmp.mx=x;
if(dy)tmp.my=(y%dy+dy)%dy;
else tmp.my=y;
if(dx&&dy)tmp.cha=x*dy-y*dx;
oklistx[tmp].insert(x);
oklisty[tmp].insert(y);
if(cnt==1){
oklistx[tmp].insert(x+dx);
oklisty[tmp].insert(y+dy);
}
}
}
printf("%lld\n",ans);
}
}
signed main()
{
int T;
T=1;
FOR(_,1,T){
solve(_);
}
return 0;
}
/*
1. 对题意的理解能否和样例对的上?
2. 每一步操作,能否和自己的想法对应上?
3. 每一步操作的正确性是否有保证?
4. 是否考虑到了所有的 case?特别是极限数据。
5. 变量的数据类型是否与其值域匹配?
6. 时间复杂度有保证吗?
7. 空间多少 MB?
*/