题解: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;
}
posted @ 2026-03-31 17:51  yutar  阅读(1)  评论(0)    收藏  举报