Codeforces1616 E. Lexicographically Small Enough
题目大意
两个长为 \(n(1\leq n\leq 10^5,\sum n\leq2\times10^5)\) 的串 \(S,T\) ,每次操作可以交换 \(S\) 中两个相邻的字符,求使 \(S\) 的字典序小于 \(T\) 所需要的最少操作次数。
思路
考虑枚举最终 \(S\) 字典序小于 \(T\) 时的公共前缀,设当前枚举到的公共前缀右端点位置为 \(pos\) ,我们在枚举右端点为 \(pos+1\) 的前缀时,将 \(S\) 后面离 \(pos+1\) 最近的对应字符移过来即可,这个操作的操作数即为距离,在后面的最近的字符可以用队列来维护。接下来的操作是找一个在当前前缀后面的最近的字符,其小于 \(pos+2\) 处的字符,我们可以记录每个初始字符位置上对应的字符现在距离当前前缀右端点 \(pos\) 的距离,当每次 \(pos+1\) 时,我们设移过去的字符的初始位置为 \(k\) ,于是我们将所有初始位置在 \([k,n]\)上的字符的距离 \(-1\) ,其余不变,并且记录一下 \(k\) 位置上的字符已经移到前缀,第二步操作时不再考虑。其他位置上的距离不用改变因为 \(pos\) 的值在第一步操作后也增加了 \(1\) ,这样距离还是不变的,于是在第二步操作者寻找前缀后面所有符合要求的字符中距离最近的即可,我们可以用支持区间修改的树状数组来维护,两次操作的结果相加即为当前所枚举的前缀下的答案,将所有答案取最小即可,复杂度 \(O(nlogn)\) 。
代码
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
//#define int LL
#define all(x) x.begin(),x.end()
#define pb push_back
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#pragma warning(disable :4996)
const double eps = 1e-8;
const LL mod = 1000000007;
const LL MOD = 998244353;
const int maxn = 200010;
int T, N;
string A, B;
LL dat0[maxn], dat1[maxn], n;
bool vis[maxn];
LL sum(LL* b, LL i)
{
LL s = 0;
while (i > 0)
{
s += b[i];
i -= i & (-i);
}
return s;
}
LL sum(LL* b, LL lo, LL hi)
{
return sum(b, hi - 1) - sum(b, lo - 1);
}
void add(LL* b, LL i, LL x)
{
while (i <= n)
{
b[i] += x;
i += i & (-i);
}
}
//
LL sum(LL i)
{
return sum(dat1, i) * i + sum(dat0, i);
}
LL sum(LL lo, LL hi)
{
return sum(hi) - sum(lo);
}
void add(LL lo, LL hi, LL x)
{
add(dat0, lo, -x * (lo - 1));
add(dat1, lo, x);
add(dat0, hi, x * hi);
add(dat1, hi, -x);
}
void solve()
{
LL ans = INF;
n = N;
queue<LL>que[26];
for (int i = 1; i <= N; i++)
dat0[i] = dat1[i] = 0, vis[i] = false;
for (int i = 0; i < N; i++)
{
que[A[i] - 'a'].push(i + 1);
add(i + 1, i + 1, i);
}
LL tmp = 0;
for (int i = 0; i < N; i++)
{
if (i != 0)
{
if (que[B[i - 1] - 'a'].empty())
break;
LL f = que[B[i - 1] - 'a'].front();
que[B[i - 1] - 'a'].pop();
vis[f] = true, tmp += sum(f - 1, f);
add(f, N, -1);
}
LL mov = INF;
for (int j = B[i] - 'a' - 1; j >= 0; j--)
{
if (!que[j].empty())
{
LL f = que[j].front(), t = sum(f - 1, f);
mov = min(mov, t);
}
}
if (mov == INF)
continue;
ans = min(ans, tmp + mov);
}
cout << (ans == INF ? -1 : ans) << endl;
}
int main()
{
IOS;
cin >> T;
while (T--)
{
cin >> N >> A >> B;
solve();
}
return 0;
}

浙公网安备 33010602011771号