寒假思维训练day17 C. Equal Frequencies

news2024/11/30 2:40:44

不知不觉已经过了差不多一个月了,坚持一件事情还是有点收获的,今天更新一道1600的构造。


寒假训练计划day17


摘要:

Part1 题意

Part2 题解 (有数学推导,latex形式)

Part3 代码 (C++版本,有详细注释)

Part4 我对构造题的归纳总结(自己对构造题的浅薄理解还有例题

题目链接(有需自取):Problem - 1781C - Codeforces


Part1 题意

题意:

规定字符串是平衡字符串当且仅当字符串中每个字符的数量相等,给定一个长度为n的字符串S,要求找到一个长度为n, n \leq 1e5的平衡字符串T,使得满足T和S的字符匹配数最多,也就是\sum_{i = 0}^{n - 1} (S[i] == T[i] ? 1 : 0)最大,输出不匹配的数量和构造出来的T。


Part2 题解

题解:

1、已知n,S, 设res为字符串的匹配数量并赋初值0。 

2、我们来观察一下平衡字符串有什么性质,因为在平衡字符串中,每个字符的数量都是相等的,假设我们知道每个字符的数量都是cnt,显然n \% cnt = 0, 1 \leq n / cnt \leq 26, 这两个数本质就是n的约数。所以我们对n分解约数,找到所有满足cnt * hve = n, cnt <= 26的数对。

3、假设我们当前考虑cnt, hve,我们需要求出当前这样分配最多能匹配几个字符,因为每个字符在原字符串中的数量不同,所以我们预处理一个Pair<int, char>序列,他们存的是S中的字符和字符的数量,并且排序,再处理出来一个该序列的前缀和序列,根据这两个序列我们可以开始求最多能匹配几个字符,我们先二分出大于等于hve的位置,再进行分了讨论,具体如下:

// u1是cnt, u2是hve, v是匹配数量     
int u1 = c, u2 = n / c;
int l = 1, r = cnt, v; 
if(u1 <= 26) {
    // 先二分
    while(l < r) {
        int mid = l + r >> 1;
        if(q[mid].ff >= u2) 
            r = mid;
        else 
            l = mid + 1;
    }
    // 分类讨论
    v = -1e18;
    if(q[l].ff >= u2) {
        if(cnt - l + 1 >= u1) 
            v = u1 * u2;
        else 
            v = (cnt - l + 1) * u2 + qs[l - 1] - 
            qs[max(0ll,l - 1 - (u1 - (cnt - l + 1)))];
    }
    else {
        v = qs[cnt] - qs[max(0ll,cnt - u1)];
    }
    // 更新res 
    if(res < v) {
        res = v;
        usu1 = u1, usu2 = u2;
    }
}

最后得到了使得匹配数量res最大的cnt, hve

4、现在我们需要利用cnt,hve逆向构造出T,首先我们对于已经处理出来的Pair<int, char>序列(已排序)的后面cnt个,注意可以会有不足的情况,我们就得补充回去,具体操作如下:

cout << n - res << endl;  // 输出最后不匹配的最小数量
vector<char> us;   
// 先处理在原字符串中的字符 
for(int i = cnt; i >= max(1ll, cnt - usu1 + 1); i--) {    
    us.push_back(q[i].ss); 
    st[q[i].ss - 'a'] = usu2;      
}

// 先将原字符串的字符有st标记的填入
for(int i = 0; i < n; i++) 
    if(st[s[i] - 'a']) { 
        ans[i] = s[i];
        st[s[i] - 'a']--;
        is_use[i] = 1;
    }

// 将后面的补上
for(int i = max(1ll, cnt - usu1 + 1) - 1; i >= 1; i--)
    us.push_back(q[i].ss), st[q[i].ss - 'a'] = usu2;  

// 如果不够再补上一些没用过的字符
for(int i = 0; i <= 25; i++) 
    if(!ot[i]) us.push_back(i + 'a'), st[i] = usu2;  
    
int l = 0;
// 最后从入序列的顺序补全字符串
for(int i = 0; i < n; i++) { 
    while(!st[us[l] - 'a']) 
        l++; 
    if(!is_use[i]) 
        ans[i] = us[l], st[us[l] - 'a']--;
}

for(int i = 0; i < n; i++) 
    cout << ans[i];
cout << endl;

Part3 代码(C++):

#include <bits/stdc++.h>
#define int long long 
#define ff first 
#define ss second 
using namespace std;
using PII = pair<int, char>; 
constexpr int N = 1e6 + 10; 
int n, m, sum; 
int ot[50], qs[50], is_use[N], st[50], cnt; 
PII q[50];
void solve() {
    string s; 
    cin >> n >> s; 
    cnt = 0;
    for(int i = 0; i <= 30; i ++ ) ot[i] = 0, st[i] = 0; 
    for(int i = 0; i < n; i ++ ) ot[s[i] - 'a'] ++, is_use[i] = 0;
    for(int i = 0; i <= 30; i ++ ) if(ot[i]) q[++ cnt] = {ot[i], 'a' + i};
    sort(q + 1, q + 1 + cnt);
    
    for(int i = 1; i <= cnt; i ++ ) qs[i] = q[i].ff + qs[i - 1];
    int res = -1e18;
    vector<char> ans(n + 1, 0); 
    int usu1,usu2;
    for(int c = 1; c <= n / c; c ++ ) 
        if(n % c == 0) {
            int u1 = c, u2 = n / c;
            int l = 1, r = cnt, v; 
            if(u1 <= 26) {
                while(l < r) {
                    int mid = l + r >> 1;
                    if(q[mid].ff >= u2) r = mid;
                    else l = mid + 1;
                }
                v = -1e18;
                if(q[l].ff >= u2) {
                    if(cnt - l + 1 >= u1) v = u1 * u2;
                    else v = (cnt - l + 1) * u2 + qs[l - 1] - qs[max(0ll,l - 1 - (u1 - (cnt - l + 1)))];
                }
                else {
                    v = qs[cnt] - qs[max(0ll,cnt - u1)];
                }
                if(res < v) {
                    res = v;
                    usu1 = u1, usu2 = u2;
                }
            }
            u1 = n / c, u2 = c;
            if(u1 <= 26) {
                l = 1, r = cnt;
                while(l < r) {
                    int mid = l + r >> 1;
                    if(q[mid].ff >= u2) r = mid;
                    else l = mid + 1;
                }
                v = -1e18;
                if(q[l].ff >= u2) {
                    if(cnt - l + 1 >= u1) v = u1 * u2;
                    else v = (cnt - l + 1) * u2 + qs[l - 1] - qs[max(0ll,l - 1 - (u1 - (cnt - l + 1)))];
                }
                else {
                    v = qs[cnt] - qs[max(0ll,cnt - u1)];
                }
                if(res < v) {
                    res = v;
                    usu1 = u1, usu2 = u2;
                }
            }
            
        }
        cout << n - res << endl; 
        vector<char> us;
        for(int i = cnt; i >= max(1ll, cnt - usu1 + 1); i -- ) {
            us.push_back(q[i].ss), st[q[i].ss - 'a'] = usu2;  
            // cout << q[i].ss << endl;
        }

        for(int i = 0; i < n; i ++ ) 
            if(st[s[i] - 'a']) { 
                // cout << s[i] << endl;
                ans[i] = s[i], st[s[i] - 'a'] --, is_use[i] = 1;
                // cout << ans[i] <<  "#";
            }
            
        for(int i = max(1ll, cnt - usu1 + 1) - 1; i >= 1; i -- )
            us.push_back(q[i].ss), st[q[i].ss - 'a'] = usu2;  
        
        for(int i = 0; i <= 25; i ++ ) if(!ot[i]) us.push_back(i + 'a'), st[i] = usu2;  
        
        int l = 0;

        for(int i = 0; i < n; i ++ ) { 
            while(!st[us[l] - 'a']) l ++; 
            if(!is_use[i]) ans[i] = us[l], st[us[l] - 'a'] --;
        }
        
        
        for(int i = 0; i < n; i ++ ) cout << ans[i];
        cout << endl;
}   
signed main() {

    int ts; 
    cin >> ts; 
    while(ts --) 
        solve(); 
    
    return 0; 
}


Part4 我对构造题的归纳总结(自己对构造题的浅薄理解) 

1、前后缀贪心,比如说观察前后缀的sum,去看以后怎么考虑最好。Problem - 1903C - Codeforces

2、双指针贪心法,考虑两端相消或者相互作用,还有就是考虑左右边界。   Problem - 1891C - Codeforces

Problem - 1907D - Codeforces

3、转换观察法,有些关系可以抽象成图,观察图的某些性质去总结规律。也可以抽象成一个集合,两个集合相等可以说明有解可构造。Problem - 1891C - Codeforces

4、打表找规律,一般没什么规律可循即可打表找规律,一般和数论有关的很喜欢考,acm也喜欢考,属于人类智慧题。Problem - 1916D - Codeforces

5、公式推导演算,常见的分为公式的等价变形、公式的化简(这个常考,一般需要先证明某些性质,可以直接抵消,一般如果原公式处理起来很复杂时就可以考虑)。Problem - 1889B - Codeforces

6、考虑奇偶数去简化问题或者分类问题,从其中的一些运算性质入手,因为奇数偶数的加减以及%运算(这个结论很重要)的结果的奇偶性是固定的,Problem - 1898C - Codeforces

7、根据性质构造模型,看看能不能分成几个块,几个不同的集合,再选择算法去解决。Problem - 1873G - Codeforces

8、考虑从小到大处理,或者是从大到小处理,有时候先处理小的对大的不会有影响,或者反过来,这样的处理顺序是最完美的。Problem - 1904D2 - Codeforces

9、边界贪心法,一般要在问题的最边界处考虑,有时候这样做结果是最优的,或者考虑边界上的影响,假如让影响最小,就使得影响<= 固定值 。 ​​​​​​Problem - E - Codeforces and Problem - 1903C - Codeforces

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1432142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux Zip解压缩命令

Zip 用法 $ zip [-选项] [-b 路径] [-t 日期] [-n 后缀名] [压缩文件列表] [-xi 列表] 默认操作是添加或替换压缩文件列表中的压缩文件条目&#xff0c;压缩文件列表可以包括特殊名称 -&#xff0c;压缩标准输入数据 Zip 是一个创建和管理 zip 文件的压缩工具 Unzip 是一个用…

使用 Python 进行自然语言处理第 3 部分:使用 Python 进行文本预处理

一、说明 文本预处理涉及许多将文本转换为干净格式的任务&#xff0c;以供进一步处理或与机器学习模型一起使用。预处理文本所需的具体步骤取决于具体数据和您手头的自然语言处理任务。 常见的预处理任务包括&#xff1a; 文本规范化——将文本转换为标准表示形式&#xff0c;…

初识C语言·编译与链接

1 翻译环境和运行环境 C语言标准ANSI C 实现C语言代码的时候 一般需要经过两种环境&#xff0c;一是翻译环境&#xff0c;二是运行环境&#xff0c;计算机能识别的是二进制的指令&#xff0c;人写完代码后通过翻译环境&#xff0c;使代码变成计算机能读懂的可执行的机器指令&a…

伦敦金重点知识:控制亏损的方法

在很多人的预期中&#xff0c;伦敦金重点知识肯定是那些涉及市场分析的方法&#xff0c;那些方法能帮助投资者一把抓住交易机会&#xff0c;在市场中建立优势。但笔者要说的是&#xff0c;那些方法固然重要&#xff0c;但笔者认为还有更加重要的&#xff0c;那就是控制亏损。控…

大模型增量预训练新技巧:解决灾难性遗忘

大家好&#xff0c;目前不少开源模型在通用领域具有不错的效果&#xff0c;但由于缺乏领域数据&#xff0c;往往在一些垂直领域中表现不理想&#xff0c;这时就需要增量预训练和微调等方法来提高模型的领域能力。 但在领域数据增量预训练或微调时&#xff0c;很容易出现灾难性…

LLM大模型

LLM 学习链接 &#xff1a; 大语言模型 LLM行业背景和市场需求 大模型的涌现能力 大模型核心前沿 大模型应用范式和职业规划

大数据 - Spark系列《四》- Spark分布式运行原理

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 目录 &#x1f360;…

200行C++代码写一个网络调试助手(TCP服务端TCP客户端)

前言 今天分享一个200行C代码写成的QT网络调试助手。 可以先看看效果 。 因为我不喜欢用QT Designer&#xff0c;因此我用的组件都是使用代码布局的&#xff0c;所以需要设计一下布局。 界面是参考的之前写的串口助手&#xff0c;就是把里面的逻辑改了改&#xff0c;因此外观…

关于网络面试题汇总

什么是TCP/IP五层模型&#xff1f;它们的作用是啥&#xff1f;基于TCP/IP实现的应用&#xff08;层协议&#xff09;有哪些&#xff1f; TCP/IP五层模型&#xff0c;从上向下分别是&#xff1a; 应用层&#xff1a;应用程序本身&#xff0c;应用层的作用是负责应用程序之间的…

比特币ETF广告战大爆发!

作者&#xff1a;秦晋 贝莱德主动发起广告攻势。 2月1日&#xff0c;据外媒Cryptoslate报道&#xff0c;贝莱德在提交给美国SEC的一份文件中显示&#xff0c;其提出一项在建筑物侧面投影比特币ETF广告计划。 据介绍&#xff0c;广告内容为&#xff1a;「IBIT」信号是一个以迈阿…

IP风险画像在企业网络安全中应用

随着企业数字化的不断深入&#xff0c;网络安全问题日益突显。IP风险画像作为一种综合性的网络安全工具&#xff0c;为企业提供了更全面的风险评估和防范手段。本文将结合一个实际案例&#xff0c;深入探讨IP风险画像在企业网络安全中的成功应用。 案例背景 一家大型金融机构…

VS2019 添加程序包

dotnet add package AlibabaCloud.SDK.Bailian20230601 来提示添加程序包 选择菜单栏 项目----管理NuGet程序包 输入程序包的名称&#xff0c;然后添加即可&#xff0c; 这只是给当前工程添加&#xff0c;并不是给VS添加&#xff0c;所以你打开新工程&#xff0c;需要使用的话…

详解WebRTC rtc::Thread实现

rtc::Thread介绍 rtc::Thread类不仅仅实现了线程这个执行器&#xff08;比如posix底层调用pthread相关接口创建线程&#xff0c;管理线程等&#xff09;&#xff0c;还包括消息队列&#xff08;message_queue)的实现&#xff0c;rtc::Thread启动后就作为一个永不停止的event l…

【图论】基环树

基环树其实并不是树&#xff0c;是指有n个点n条边的图&#xff0c;我们知道n个点n-1条边的连通图是树&#xff0c;再加一条边就会形成一个环&#xff0c;所以基环树中一定有一个环&#xff0c;长下面这样&#xff1a; 由基环树可以引申出基环内向树和基环外向树 基环内向树如…

【开源】WordPress一键崩溃宕机插件(整活娱乐)

插件介绍 可一键实现Wordpress崩溃宕机的整活向插件&#xff08;请勿用于非法途径&#xff0c;仅供整活娱乐&#xff09;。鼓励关注网站性能的提升&#xff0c;以提供更好的用户体验&#xff0c;提倡为用户提供良好体验和高效速度的原则。 介绍 长期以来&#xff0c;人们都在…

WordPress从入门到精通【安装部署】

初识WordPress WordPress&#xff0c;简称WP&#xff0c;其简称的由来是取英文单词“word”与“press”的首字母 WP中文官网 1WP主站&#xff08;英文&#xff09; 官方标称&#xff0c;已有43%的网站在使用WordPress WordPress亮点 WP使用PHP语言开发&#xff0c;兼容性极…

深度学习/自动驾驶数据集大集合(目标检测/图像分割/语义分割/图像分类/)

深度学习和自动驾驶技术的发展离不开高质量的数据集&#xff0c;这些数据集对于训练和验证各种自动驾驶算法和模型起着至关重要的作用。深度学习/自动驾驶数据集大集合是一项汇集了多种场景、多种数据类型的数据资源&#xff0c;旨在为深度学习和自动驾驶领域的研究者和从业者提…

设计模式-行为型模式(上)

行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式&#xff0c;前者采用继承机制来在类间分派行为&…

【服务器】RAID(独立磁盘冗余阵列)

RAID&#xff08;独立磁盘冗余阵列&#xff09; 一、RAID的介绍二、RAID的分类#2-1 RAID 02-2 RAID 1#2-3 RAID 32-4 RAID 52-5 RAID 62-6 RAID 10(先做镜像&#xff0c;再做条带化)2-7 RAID 01&#xff08;先做条带&#xff0c;再做镜像&#xff09;2-8 RAID比较 三、磁盘阵列…

CSDN文章导出工具

源码地址&#xff1a; github:https://github.com/lishuangquan1987/CSDNExportergitee:https://gitee.com/lishuangquan1987/csdnexporter 介绍 最近有CSDN博客导出来的需求&#xff0c;翻看了很多开源工具&#xff0c;都不能用或者不好用&#xff0c;于是决定自己做一个。…