Hamming Distance(贪心,函数,构造)

题意

汉明距离:给定两个长度相等的字符串(a)(b),汉明距离(H(a, b) = sum_{i = 1}^{|a|}(a_i e b_i))

现在给定两个长度相等、全由小写字母构成的字符串(a)(b)。求字典序最小的字符串(s),使得(H(a, s) = H(b, s))

数据范围

(1 leq T leq 100)

(1 leq |a| leq 10000)

思路

定义函数(f(x) = H(a, x) - H(b, x)),我们的目标是找一个(s),使得(f(s) = 0)

我们可以看一下(x)的每一位对函数值的贡献,不妨设可以使函数值增加(t)

  • (a_i e b_i)(s_i = a_i),则(t = 1)

  • (a_i e b_i)(s_i = b_i),则(t = -1)

  • 其他情况,(t = 0)

因此,可以得出结果,通过调整(x),可以使得(f(x))连续变化。

为了保证字典序最小,我们要尽可能的选择较小的字符,但是存在一个问题就是我前面选了较小的字符,但是后面无论怎么选都无法满足条件了。

为了应对上述情况,我们采用一个预处理。就是统计字符串后缀可以使得(f(x))产生多大的变化范围。因此,定义一个(suf[i])数组,表示的是(i sim |a|)范围内(f(x))的变化幅度。

即,统计(i sim |a|)范围内,(a_i e b_i)的个数。因此,在第(i)位从小到大枚举每个字符,如果当前的字符满足(|f(x_i)| leq suf_{i + 1}),那么就可以选这个字符。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10010;

char s1[N], s2[N];
char ans[N];
int suf[N];

bool solve(char ch, int idx, int &dif)
{
    int tmp = dif + (ch != s1[idx]) - (ch != s2[idx]);
    if(abs(tmp) <= suf[idx + 1]) {
        dif = tmp;
        ans[idx] = ch;
        return true;
    }
    return false;
}

int main()
{
    int T;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; cas ++) {
        scanf("%s%s", s1, s2);
        memset(suf, 0, sizeof(suf));
        memset(ans, '', sizeof(ans));
        int len = strlen(s1);
        for(int i = len - 1; i >= 0; i --) {
            suf[i] = suf[i + 1];
            if(s1[i] != s2[i]) suf[i] ++;
        }
        int dif = 0;
        for(int i = 0; i < len; i ++) {
            for(int j = 0; j < 26; j ++) {
                if(solve(j + 'a', i, dif)) break;
            }
        }
        printf("Case %d: %s
", cas, ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/miraclepbc/p/14381000.html