在此纪念考试时忘开 long long 的我。
题意
给你两个字符串,每次可以交换字符串一中相邻的两个字符,请你求出最少交换几次可以使字符串一比字符串二的字典序更小。
思路
贪心部分
贪心,每次分为以下两种情况。
-
在此位置确定字符串一的字典序更小。
-
在此位置以后确定字符串一的字典序更小。
什么意思呢?
举个例子,假设两个字符串分别为:
qaq
qwq
如果我们要在第一个字符时确定字符串一的字典序更小,必须使字符串一的第一个字符比字符串二的第一个字符的字典序更小。
在这两个字符串中,满足条件的字符串一只有:
aqq
如果我们要在第二个字符时确定字符串一的字典序更小,必须使字符串一的第二个字符比字符串二的第二个字符的字典序更小。
除此之外,还必须保证之前已改变的字符串一致,如果不一致,字典序就会不同,后面的字符也就不需要再管了。
在这两个字符串中,满足条件的字符串一只有:
qaq
所以我们只需要找到距离此处最近,且要么目前的字符串一比目前的字符串二的字典序小,要么目前的字符串一与目前的字符串二的字典序相等的情况即可。
只要找到此处字典序更小的情况,就可以记一次答案,而在前面的字符相等的情况下,只需要找出后来字符串一的某个字符的字典序更小的情况再加上前面的字符相等的情况的最小交换数即可。
其他部分
接下来,我们要考虑在交换过程中,后面的字符向前移动,可以看做前面交换过的字符在做相对运动,即向后移动一位。
所以,对于每次移动(指后面的字符移动到前面的某个位置,也就是进行多次交换),只需要让在它前面且在它移动到的位置的后面的所有字符的位置加上一即可。
此处可以用求和的方式,找到每一次移动前的最初始位置(刚输入时的位置),并将这个位置的值变为一,前面每一个字符串的位置就是从目前位置的值加到最后一个位置的值。
此处可以用分块或线段树等多种方式求出和,本人的代码就是用的分块。
时间复杂度为 O ( n n ) O(n \sqrt n) O(nn)。
AC 代码
#include<bits/stdc++.h>
using namespace std;
char c1[100005],c2[100005];
long long n,sum[30],w[30][100005],u[30],now=0,ans=1e12,h[100005],k[100005],kl=0,ks=0;
int qh(int x)
{
long long hz=0,nks=(x-1)/kl+1;
for(int i=x;i<=min(nks*kl,n);i++)
{
hz+=h[i];
}
for(int i=nks+1;i<=ks;i++)
{
hz+=k[i];
}
return hz;
}
void become(int x)
{
for(int i=1;i<=ks;i++)
{
if(((i-1)*kl)+1<=x&&(i*kl)>=x)
{
k[i]++;
break;
}
}
return;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
ans=1e12;
cin>>n;
kl=sqrt(n);
if(n%kl==0)
{
ks=n/kl;
}
else
{
ks=n/kl+1;
}
for(int i=1;i<=n;i++)
{
cin>>c1[i];
}
for(int i=1;i<=ks;i++)
{
k[i]=0;
}
long long g=100000;
for(int i=1;i<=min(ks*kl,g);i++)
{
h[i]=0;
}
for(int i=1;i<=n;i++)
{
cin>>c2[i];
}
for(int i=0;i<=25;i++)
{
sum[i]=0;
u[i]=0;
for(int j=1;j<=n;j++)
{
w[i][j]=-1;
}
}
for(int i=1;i<=n;i++)
{
sum[int(c1[i]-'a')]++;
w[int(c1[i]-'a')][sum[int(c1[i]-'a')]]=i;
}
now=0;
for(int i=1;i<=n;i++)
{
if(w[int(c2[i]-'a')][u[int(c2[i]-'a')]+1]==-1)
{
for(int j=0;j<c2[i]-'a';j++)
{
if(w[j][u[j]+1]!=-1)
{
ans=min(ans,now+abs(i-(w[j][u[j]+1]+qh(w[j][u[j]+1]))));
}
}
break;
}
else
{
for(int j=0;j<c2[i]-'a';j++)
{
if(w[j][u[j]+1]!=-1)
{
ans=min(ans,now+abs(i-(w[j][u[j]+1]+qh(w[j][u[j]+1]))));
}
}
u[int(c2[i]-'a')]++;
now+=abs(i-(w[int(c2[i]-'a')][u[int(c2[i]-'a')]]+qh(w[int(c2[i]-'a')][u[int(c2[i]-'a')]])));
h[w[int(c2[i]-'a')][u[int(c2[i]-'a')]]]++;
become(w[int(c2[i]-'a')][u[int(c2[i]-'a')]]);
}
}
if(ans==1e12)
{
cout<<-1<<endl;
}
else
{
cout<<ans<<endl;
}
}
return 0;
}