CF254C Anagram

在这里插入图片描述

题目描述

如果我们能够重新排列字符串 x x x 中的字母,从而得到与字符串 y y y 完全相同的字符串,那么字符串 x x x 就是字符串 y y y 的同字母异序词。例如,字符串 “DOG” 和 “GOD” 是同字母异序词,字符串 “BABA” 和 “AABB” 也是同字母异序词,但字符串 “ABBAC” 和 “CAABA” 不是。

给你两个长度相同且由大写英文字母组成的字符串 s s s t t t 。你需要从字符串 s s s 得到字符串 t t t 的一个同字母异序词。你被允许执行替换操作:每次操作是将字符串 s s s 中的某个字符替换为任意其他字符。以最少的替换操作次数得到字符串 t t t 的一个同字母异序词。如果你能以最少的操作次数得到字符串 t t t 的多个同字母异序词,那么请得到字典序最小的那个。

字符串的字典序就是我们熟悉的 “字典” 顺序。形式上,如果对于某个 k k k 1 ≤ k ≤ n 1 \leq k \leq n 1kn),有 p 1 = q 1 p_{1}=q_{1} p1=q1 p 2 = q 2 p_{2}=q_{2} p2=q2,……, p k − 1 = q k − 1 p_{k - 1}=q_{k - 1} pk1=qk1 p k < q k p_{k} < q_{k} pk<qk,那么长度为 n n n 的字符串 p p p 在字典序上小于长度相同的字符串 q q q 。这里字符串中的字符从 1 开始编号。字符串中的字符按照字母顺序进行比较。

输入格式

输入由两行组成。第一行包含字符串 s s s ,第二行包含字符串 t t t 。这两个字符串长度相同(长度范围是从 1 到 1 0 5 10^{5} 105 个字符)且都由大写英文字母组成。

输出格式

在第一行输出 z z z —— 从字符串 s s s 得到字符串 t t t 的一个同字母异序词所需的最少替换操作次数。在第二行输出在 z z z 次操作下能够得到的字典序最小的同字母异序词。

输入输出样例 #1

输入 #1

CDBABC
ADCABD

输出 #1

2
ADBADC

说明/提示

第二个样例中,有八个字符串 t t t 的同字母异序词可以通过恰好替换字符串 s s s 中的两个字母得到,它们分别是:“ADBADC”、“ADDABC”、“CDAABD”、“CDBAAD”、“CDBADA”、“CDDABA”、“DDAABC”、“DDBAAC” 。这些同字母异序词按字典序列出。字典序最小的同字母异序词是 “ADBADC” 。

题解

题目理解

本题的核心任务是将字符串 s s s 通过最少的字符替换操作,转换为字符串 $ t $ 的变位词。如果存在多个最少操作次数的结果,要输出字典序最小的那个。

题目分析

我们可以很快得出 a n s = ∑ i = 1 n ∣ a i − b i ∣ ans = \sum_{i=1}^{n} |a_i - b_i| ans=i=1naibi 的最小步骤为 a n s / 2 ans / 2 ans/2
然后我们可以通过枚举 S S S,并找字母来替代他,来求最小的字典序字符串。

Code

#include <bits/stdc++.h>

using namespace std;

string A, B;
int a[30], b[30];
int cnt1[30], cnt2[30];
void read()
{
	cin >> A;
	cin >> B;
}
void solve()
{
	for (int i = 0; i < A.size(); i++)
	{
		a[A[i] - 'A' + 1]++;
	}
	for (int i = 0; i < B.size(); i++)
	{
		b[B[i] - 'A' + 1]++;
	}
	int ans = 0;
	for (int i = 1; i <= 26; i++)
	{
		int num = abs(a[i] - b[i]);
		ans += num;
		if (a[i] >= b[i])
		{
			cnt1[i] += num;
		}
		else
		{
			cnt2[i] += num;
		}
	}
	cout << ans / 2 << endl;
	for (int i = 0; i < A.size(); i++)
	{
		a[A[i] - 'A' + 1]--;
		if (cnt1[A[i] - 'A' + 1])
		{
			for (int j = 1; j <= 26; j++)
			{
				if (j >= A[i] - 'A' + 1 && a[A[i] - 'A' + 1] >= cnt1[A[i] - 'A' + 1])
				{
					break;
				}
				if (cnt2[j])
				{
					cnt1[A[i] - 'A' + 1]--;
					cnt2[j]--;
					A[i] = char('A' + j - 1);
					break;
				}
			}
		}
			
	}
	cout << A << endl;
}


int main()
{
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	read();
	solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值