CF1697C awoo's Favorite Problem
https://www.luogu.com.cn/problem/CF1697C
船新做法。
考虑 \(ab \to ba\),\(bc\to cb\) 都可以看成邻位交换。
即记 \(a=1,b=2,c=3\),能交换 \(i,i+1\) 当且仅当 \(v_i+1=v_{i+1}\)。
然后交换的过程就是冒泡排序,但因为我们只需要判断是否可行。
所以我们可以按在 \(b\) 中的相对顺序对 \(a\) 进行重编号,那么就转为要让 \(a\) 按从小到大排列,每次可以交换相邻 2 个数(满足上述规则)
考虑 2 个数会邻位交换当且仅当 \(i<j,nex_i>nex_j\),\(nex\) 为交换后的编号。
然后就限制一下加个树状数组就好了。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(1e5+5);
struct node {
int x,fl;
}v[N];
int n,p1[N],p2[N],p3[N],tot1,tot2,tot3;
char a[N],b[N];
struct BIT {
#define lowbit(x) (x&(-x))
int sum[N];
void upt(int x,int v) {
while(x<=n) sum[x]+=v,x+=lowbit(x);
}
int qry(int x) {
int res=0;
while(x) res+=sum[x],x-=lowbit(x);
return res;
}
}T1,T2,T3,Tall;
void solve() {
cin>>n>>a+1>>b+1; tot1=tot2=tot3=0;
int cnta=0,cntb=0,cntc=0;
for(int i=1;i<=n;i++) {
if(a[i]=='a') ++cnta;
else if(a[i]=='b') ++cntb;
else ++cntc;
}
for(int i=1;i<=n;i++) {
if(b[i]=='a') --cnta;
else if(b[i]=='b') --cntb;
else --cntc;
}
if(cnta!=0||cntb!=0||cntc!=0) {
cout<<"NO\n"; return ;
}
for(int i=1;i<=n;i++) {
if(b[i]=='a') p1[++tot1]=i;
else if(b[i]=='b') p2[++tot2]=i;
else p3[++tot3]=i;
}
int t1=0,t2=0,t3=0;
for(int i=1;i<=n;i++) {
if(a[i]=='a') ++t1,v[i].x=p1[t1],v[i].fl=1;
else if(a[i]=='b') ++t2,v[i].x=p2[t2],v[i].fl=2;
else ++t3,v[i].x=p3[t3],v[i].fl=3;
}
bool ans=1;
for(int i=1;i<=n;i++) {
// for(int j=1;j<i;j++) {
// if(v[j].x>v[i].x) {
// if(v[j].fl+1!=v[i].fl) {
// ans=0; break ;
// }
// }
// }
int qwq=Tall.qry(n)-Tall.qry(v[i].x);
if(v[i].fl==1) {
if(qwq) ans=0;
T1.upt(v[i].x,1);
} else if(v[i].fl==2) {
int qaq=T1.qry(n)-T1.qry(v[i].x);
if(qaq!=qwq) ans=0;
T2.upt(v[i].x,1);
} else {
int qaq=T2.qry(n)-T2.qry(v[i].x);
if(qaq!=qwq) ans=0;
T3.upt(v[i].x,1);
}
Tall.upt(v[i].x,1);
}
for(int i=0;i<=n;i++) T1.sum[i]=T2.sum[i]=T3.sum[i]=Tall.sum[i]=0;
if(ans) cout<<"YES\n";
else cout<<"NO\n";
}
signed main() {
cin.tie(0); ios::sync_with_stdio(false);
int T; cin>>T; while(T--) solve();
}