题解:P15572 [USACO26FEB] Swap to Win B
解析
提供一种不一样的实现方式,时间复杂度 \(O(Tnm)\)。
初始的构造思路是对于 \(t\) 的每个位置 \(i\),找到一个对应的字符 \(s_{x,j}=t_j\),再通过一次操作 1 来调整到 \(s_{x,i}\),再通过一次操作 2 交换到 \(s_{1,i}\)。
改变一下思路,考虑对于 \(s_i\) 的每个位置 \(j\),如果 \(s_1\) 中缺少 \(s_{i,j}\),那么就交换上去。
具体实现是,先预处理出一个 \(pos_c\) 表示 \(t\) 中所有字母 \(c\) 的位置下标。然后然后遍历所有 \(s_{i,j}\),若 \(s_1\) 中缺少 \(s_{i,j}\),即 \(pos_{s_{i,j}}\) 中存在元素,则取出其中一个元素 \(x\),将 \(s_{i,j}\) 交换至 \(s_{1,x}\)。但是这样实际上有两步交换,第一步是 \(s_{i,j}\leftrightarrows s_{i,x}\),第二步是 \(s_{i,x} \leftrightarrows s_{1,x}\),这就导致了交换到 \(s_{i,j}\) 和 \(s_{i,x}\) 的字母有可能实际上是有用的,为了避免忽略掉这些字母,我们需要再进行判断。整个过程类似于 BFS。
但是要注意,在遍历 \(s_1\) 时,不能把已经在正确位置上的字符给交换了。
代码
#include <bits/stdc++.h>
#define ls(p) ((p) << 1)
#define rs(p) (((p) << 1) | 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e6 + 5,M = 6e6,mod = 998244353;
vector<int> cnt[N];
int inq[N];
struct S{
int op,x,y,z;
void print(){
cout<<op<<" "<<x<<" "<<y<<" "<<z<<'\n';
}
};
vector<S> res;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--){
int n,m;
cin>>n>>m;
string t;
string s[n + 1];
vector<int> pos[26];
cin>>t;
for(int i=0;i<m;i++){
pos[t[i] - 'a'].push_back(i);
}
for(int i=1;i<=n;i++){
cin>>s[i];
queue<int> q;
for(int j=0;j<m;j++){
q.push(j);
inq[j] = true;
}
while(!q.empty()){
int j = q.front();
q.pop();
inq[j] = false;
if(!pos[s[i][j] - 'a'].size() || (i == 1 && s[i][j] == t[j])) continue;
int p = pos[s[i][j] - 'a'].back();
res.push_back({1,i,p + 1,j + 1});
res.push_back({2,1,i,p + 1});
pos[s[i][j] - 'a'].pop_back();
swap(s[i][j],s[i][p]);
swap(s[i][p],s[1][p]);
if(!inq[j] && pos[s[i][j] - 'a'].size()) q.push(j),inq[j] = true;
if(!inq[p] && pos[s[i][p] - 'a'].size()) q.push(p),inq[p] = true;
}
}
cout<<res.size()<<'\n';
for(int i=0;i<res.size();i++){
res[i].print();
}
res.clear();
assert(t == s[1]);
}
return 0;
}

浙公网安备 33010602011771号