Codeforces 551B ZgukistringZ (字符串处理)

本文探讨了如何通过编程技巧解决一个复杂的字符串匹配问题。教授GukiZ需要将字符串a转换为字符串k,使得k包含尽可能多的与字符串b或c不重叠的子串。文章详细介绍了算法思路,包括线性规划、贪心策略以及最终正确的枚举法求解过程,并提供了代码实现。同时,文章分析了贪心策略的局限性,强调了正确求解方法的重要性。

最近已经很久没有弄csdn和刷题了,感觉自己水了不少,还是要赶紧刷题准备比赛才行啊。

题目介绍

Professor GukiZ doesn’t accept string as they are. He likes to swap some letters in string to obtain a new one.

GukiZ has strings a, b, and c. He wants to obtain string k by swapping some letters in a, so that k should contain as many non-overlapping substrings equal either to b or c as possible. Substring of string x is a string formed by consecutive segment of characters from x. Two substrings of string x overlap if there is position i in string x occupied by both of them.

GukiZ was disappointed because none of his students managed to solve the problem. Can you help them and find one of possible strings k?

Input
The first line contains string a, the second line contains string b, and the third line contains string c (1 ≤ |a|, |b|, |c| ≤  105 , where |s| denotes the length of string s).

All three strings consist only of lowercase English letters.

It is possible that b and c coincide.

Output
Find one of possible strings k, as described in the problem statement. If there are multiple possible answers, print any of them.

题目说的是我们要重新组合string a,每次可以swap a 的任意两个字符,使输出的string满足不重叠连续字串能和 b/c 匹配的次数最多。


算法

读完题之后就觉得有点那种线性规划的意思,就是那种b,c两个字符串的线性组合。然后因为对 a 的交换任意两个字符的这个操作可以得到 a 中字符的任意排列,所以我们也就不在乎最终得到的字符串是否合法,只要和 a 具有相同的字母统计即可了。

比赛的时候贪心了一发,先算出两个数res1和res2分别代表如果只匹配b和只匹配c能够有多少个, 然后挑选最大的那个数字(比如说是res1),先输出res1个b,然后再做一次统计看还有多少个c可以被输出。之后输出够c之后,再把剩余的字符串都输出出来。这种方法一直被卡在test12,知道比赛结束也没有AC。

之后看到了别人的评论,说明贪心其实是不可以的。举个例子来说

aacaacbbaac
aac
ab

这组数据,如果用贪心法的话会是3,但是最优解却是4,估计是我比赛的时候脑子有些不灵光,想了一个错误的证明并且走了错误的道路。

所以最后的解决方案就是枚举所有可行解,t1个b,t2个c,取t1+t2最大的时候的匹配模式输出。但是这里还是要进行一发提前检测的,同上,看res1和res2哪个大,就从哪个开始枚举,否则当 res1=0 res2!=0 的时候就会跪。


代码

#include "stdafx.h"

#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <memory.h>
#include <cassert>
#include <string>
#include <queue>

using namespace std;
int n, m, p, q, t, r;
long long res;
string s1, s2, s3;
int a[30]; // a的统计数据
int b[30]; // b的统计数据
int c[30]; // c的统计数据
int aa[30]; // 这个是为了输出时候的方便,用aa代替a被修改

int main() {
    cin >> s1 >> s2 >> s3; // 输入的a,b,c字符串
    for (int i = 0; i < s1.length(); i++) {
        a[s1[i] - 'a']++;
        aa[s1[i] - 'a']++;
    }
    for (int i = 0; i < s2.length(); i++) {
        b[s2[i] - 'a']++;
    }
    for (int i = 0; i < s3.length(); i++) {
        c[s3[i] - 'a']++;
    }

    // 检验如果只输出b能有多少个
    int temp = 10000000;
    for (int i = 0; i <= 25; i++) {
        if (b[i] == 0) continue;
        temp = min(a[i] / b[i],temp);
    }
    // 检验如果只输出c能有多少个
    int temp2 = 10000000;
    for (int i = 0; i <= 25; i++) {
        if (c[i] == 0) continue;
        temp2 = min(a[i] / c[i], temp2);
    }

    int sum = 0;
    int res1 = 0; int res2 = 0;
    if (temp > temp2) {
        for (int i = 1; i <= temp; i++) {
            // 枚举输出b的个数
            for (int t = 0; t <= 25; t++) {
                aa[t] = a[t];
            }

            for (int kk = 0; kk < s2.length(); kk++) {
                aa[s2[kk] - 'a'] -= i;
            }
            // 在此输出b的数量下,还有多少个c能被输出
            int temp2 = 10000000;
            for (int i = 0; i <= 25; i++) {
                if (c[i] == 0) continue;
                temp2 = min(aa[i] / c[i], temp2);
            }

            if (temp2 + i > sum) {
                sum = temp2 + i;
                res1 = i; res2 = temp2;
            }
        }
    }
    else {
        for (int i = 1; i <= temp2; i++) {
            // 输出C的个数
            for (int t = 0; t <= 25; t++) {
                aa[t] = a[t];
            }

            for (int kk = 0; kk < s3.length(); kk++) {
                aa[s3[kk] - 'a'] -= i;
            }
            // 在此输出C的数量下,还有多少个B能被输出
            int temp = 10000000;
            for (int i = 0; i <= 25; i++) {
                if (b[i] == 0) continue;
                temp = min(aa[i] / b[i], temp);
            }

            if (temp + i > sum) {
                sum = temp + i;
                res2 = i; res1 = temp;
            }
        }
    }
    for (int i = 1; i <= res1; i++) {
        cout << s2;
    }
    for (int i = 0; i < s2.length(); i++) {
        a[s2[i] - 'a'] -= res1;
    }
    for (int i = 1; i <= res2; i++) {
        cout << s3;
    }
    for (int i = 0; i < s3.length(); i++) {
        a[s3[i] - 'a'] -= res2;
    }
    for (int i = 0; i <= 25; i++) {
        for (int j = 0; j < a[i]; j++) {
            cout << (char)(i + 'a');
        }
    }
    return 0;
}

照例自我介绍:

ID: Oh2
github: http://github.com/oh233
csdn: http://blog.youkuaiyun.com/oh233
个人网站: http://oh233.com
知乎: http://www.zhihu.com/people/qi-hao-zhi-65

### 关于河南财经政法大学字符串处理的教学内容 在讨论河南财经政法大学关于字符串处理的教学内容之前,可以先理解字符串处理的基础概念以及其应用范围。通常情况下,高校中的计算机科学课程会涉及字符串操作的相关知识点,这些知识点可能包括但不限于字符串的创建、访问、修改、查找、替换和排序等。 对于去重并排序后的字符串处理[^1],可以通过 Python 编程语言实现如下功能: #### 去重并排序字符串的代码示例 以下是基于 Python 的一个简单示例,用于展示如何对字符串进行去重和排序的操作: ```python def remove_duplicates_and_sort(input_string): unique_characters = sorted(set(input_string)) # 使用 set 去重,并通过 sorted 排序 result_string = ''.join(unique_characters) # 将字符列表重新组合成字符串 return result_string input_str = "hello world" output_str = remove_duplicates_and_sort(input_str) print(f"原始字符串: {input_str}") print(f"去重并排序后的字符串: {output_str}") ``` 上述代码展示了如何去掉输入字符串中的重复字符并将剩余字符按字母顺序排列。此方法利用了 `set` 数据结构来自动去除重复项,随后使用内置函数 `sorted()` 对结果集合内的元素进行升序排序。 #### 可能的教学资源方向 虽然具体到河南财经政法大学的实际教材或讲义无法直接获取,但从一般性的教育材料推测,该校可能会采用以下几种形式作为教学辅助工具: 1. **官方文档与教程** 学校教师往往会推荐学生阅读编程语言(如 Python)的官方文档,因为这是学习任何新库或者模块最权威的第一手资料。 2. **在线平台练习题** LeetCode, HackerRank 和 Codeforces 这样的网站提供了大量针对字符串算法设计的问题,适合用来巩固课堂所学理论知识。 3. **开源书籍与笔记分享** GitHub 上存在许多由开发者贡献的技术电子书项目,其中不乏专注于数据结构与算法领域的内容,可供师生共同探讨交流。 综上所述,在没有确切获得河南财经政法大学内部使用的特定教材前提下,以上提到的方法论和技术手段均具有普适价值,能够帮助初学者掌握基本的字符串处理技巧。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值