「FSLOI Round I」迷雾 题解

· · 题解

解题思路

维护坐标是简单的,注意走到边界处时及时停下即可。难点在于修改操作。

Subtask 1

由于 q=1,所以输出移动一次后的位置即可。

Subtask 2

#### Subtask 3 首先需要发现对 $c_i$ 进行偶数次修改等于没有修改,进行奇数次修改等于修改一次。 由于 $k=1$,所以每次修改的都是连续段,提高组选手可以考虑一个线段树砸上去。但是这是基础赛,所以我们考虑差分。维护一个 $flag$ 代表是否修改。如果第 $i$ 次移动结束后需要修改,先把 $flag$ 异或上 $1$,再维护一个差分数组 $cnt$,将 $cnt_{i+b_i+1}$ 也异或上 $1$。在第 $i$ 次移动前,让 $flag$ 异或上当前的 $cnt_i$ 即可。 #### Subtask 4 & 5 发现 $k$ 的加入并没有本质影响。实际上就是把 $c$ 序列按照下标除以 $k$ 的余数分成了 $k$ 组。提高组选手可以考虑 $k$ 个线段树砸上去,并没有刻意卡线段树。但是这是基础赛,所以我们考虑 $k$ 个差分砸上去即可。和 Subtask 3 没有本质区别。 ### 代码示例 ```cpp #include<bits/stdc++.h> using namespace std; #define int long long int n,m,k,q; string s[510]; char c[200010]; int a[200010],b[200010]; int cnt[200100][25],flg[25]; //修改的函数 char Change(char x){ if(x=='U') return 'D'; if(x=='D') return 'U'; if(x=='L') return 'R'; if(x=='R') return 'L'; } signed main(){ cin>>n>>m>>q>>k; for(int i=1;i<=n;i++) cin>>s[i],s[i]=" "+s[i]; for(int i=1;i<=q;i++) cin>>c[i]>>a[i]>>b[i]; int x=1,y=1; for(int i=1;i<=q;i++){ int id; //判断除以k的余数 if(i%k==0) id=k; else id=i%k; flg[id]^=cnt[i][id]; //修改 if(flg[id]) c[i]=Change(c[i]); //移动 if(c[i]=='U') x=max(1ll,x-a[i]); if(c[i]=='D') x=min(n,x+a[i]); if(c[i]=='L') y=max(1ll,y-a[i]); if(c[i]=='R') y=min(m,y+a[i]); //修改,利用差分思想 if(s[x][y]=='X') flg[id]^=1,cnt[i+b[i]*k+k][id]^=1; } cout<<x<<" "<<y<<endl; return 0; } ``` 事实上空间复杂度可以优化到 $\Theta(n)$,因为上述代码中 $cnt$ 数组实际用到的空间只有 $\Theta(n)$。 ```cpp #include<bits/stdc++.h> using namespace std; #define int long long int n,m,k,q; string s[510]; char c[200010]; int a[200010],b[200010]; int cnt[200100],flg[25]; //修改的函数 char Change(char x){ if(x=='U') return 'D'; if(x=='D') return 'U'; if(x=='L') return 'R'; if(x=='R') return 'L'; } signed main(){ cin>>n>>m>>q>>k; for(int i=1;i<=n;i++) cin>>s[i],s[i]=" "+s[i]; for(int i=1;i<=q;i++) cin>>c[i]>>a[i]>>b[i]; int x=1,y=1; for(int i=1;i<=q;i++){ int id; //判断除以k的余数 if(i%k==0) id=k; else id=i%k; flg[id]^=cnt[i]; //修改 if(flg[id]) c[i]=Change(c[i]); //移动 if(c[i]=='U') x=max(1ll,x-a[i]); if(c[i]=='D') x=min(n,x+a[i]); if(c[i]=='L') y=max(1ll,y-a[i]); if(c[i]=='R') y=min(m,y+a[i]); //修改,利用差分思想 if(s[x][y]=='X') flg[id]^=1,cnt[i+b[i]*k+k]^=1; } cout<<x<<" "<<y<<endl; return 0; } ```