题意:一个人有两个字符串A和B,两个字符串具有相同的长度n\((|A| = |B| = n)\),包含前20个小写字符('a'到't')。每一次操作,这个人可以选择A字符串中字符相同的字母,然后从中选择一些位置,并把这些位置的字母变大。求字符串A变到字符串B的最少操作次数。
分析:我们可以贪心地进行操作,对于"aab"--->"bbc",我们可以先把"aa"变成"bb",那么"aab"--->"bbb",然后把第三个字母'b'变成'c',那么'aab'--->'bbc'。我们可以通过从小到大枚举每个字母,检测字符串A和给定字母是否相同,然后求取对应位置的字母和这个字母相隔的差,在这些差中取最小值,意思是指对于"aabc"--->"bdec",如果枚举到了'a'字母,我们可以得到第一个字符串的第一个字母'a'和第二个字符串的第一个字母'b'的差1,第一个字符串的第二个字母'a'和第二个字符串的的第二个字母'd'之间的差3,对这个差取最小值,是我们每次要变化的值,对于所有的a,加上这个1,那么'bbbc'->'bdec'。我们可以通过这个贪心策略,得到最优解。每次枚举的一个字母,都可以把A字符串相同的字母消除掉。所以最多不超过20次。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <algorithm>
using namespace std;
const int N = 100005;
const int inf = 0x3f3f3f3f;
char a[N], b[N];
int len;
int modify(int c)
{
int mn = inf;
for (int i = 1; i <= len; ++i)
{
if (a[i] == b[i]) continue;
if (a[i] - 'a' == c)
{
if (a[i] > b[i]) return -1;
mn = min(mn, b[i] - a[i]);
}
}
for (int i = 1; i <= len; ++i)
{
if (a[i] - 'a' == c)
{
if (a[i] < b[i])
{
a[i] += mn;
}
}
}
//bool flag = true;
if (mn == inf) return 0;
return 1;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
scanf("%s%s", a + 1, b + 1);
len = strlen(a + 1);
bool flag = false;
int res = 0;
//枚举20个字符
for (int i = 0; i < 20; ++i)
{
int g = modify(i);
if (g == -1)
{
flag = true;
break;
}
res += g;
}
if (!flag)
{
printf("%d\n", res);
}
else
{
printf("-1\n");
}
}
return 0;
}