寒假思维训练计划day16 A. Did We Get Everything Covered?

今天更新一道1月27号晚上div2的C题作为素材,感觉用到了我的构造题总结模型,我总结了一系列的模型和例题。


摘要:

Part1 定义"边界贪心法"

Part2 题意

Part3 题解

Part4 代码

Part5 思维构造题 模型和例题


Part1 边界贪心法(该题所用到的模型):

边界贪心法: 对于整体而言,我们去除已经定好的情况,剩下难以确定的情况,我们从其最边缘的位置去考虑、去假设;一般要在问题的最边界处考虑,一般最边界决定总体的走向,后面会给例题以及其它的模型及其例题。


Part2 题意:Problem - A - Codeforces

题意:

给定,再给定一个长度为的字符串S,该字符串满足只包含前k个小写字母字符, 要求判断能否找到所有的长度为且字符组成只包含前个小写字母字符的字符串为S的子序列(删除一些元素后,其余元素顺序不变而组成的序列),能输出"YES",不能输出"NO",并构造出该字符串,它满足不是S的子序列。


Part3 题解:

题解:

1、已知:

2、我们不妨从头到尾遍历,当满足划分一个块,即块中元素恰好包含了所有的前个元素,当出现必然是最后一个块 ,因为它往后无法得到全部元素,一直到最后才能满足,否则就可以一直往后合并。

3、接下来,我么分好了块,假设有:表示分出的块,

我们进行分类讨论

3.1 当那我们必然能从每个块分别拿出任意字符,组成长度为n的子序列。

3.2 当,此时我们证明一定是无解的,

3.2.1 首先我们证明第一个命题,所有满足块的最后一个元素必然只存在一个在当前块中:当最后一个元素有两个,我们必然可以让块的右边界往左边移动,矛盾。

3.2.2 证明从前往后每次取块中最后一个元素的序列一定是唯一的:已知有, 其中满足的是:,当舍弃最后一个块的元素,我们知道该块中仅仅只有一个这样的元素(由3.2.1得), 只能在前面的块找到 ,显然也只由一个在块中,所以一直往前,必然无法找到新的可替代的,所以唯一。

3.2.3 所以取每个块的最后一个元素得到的,并且它是唯一的,我们只需要在后面补上任意元素,使得就一定不是S的子序列。


Part4 代码(C++)

C++代码(边界贪心法):

cpp 复制代码
#include <bits/stdc++.h>
#define int long long 
#define ff first 
#define ss second 
using namespace std; 
using PII = pair<int, int>; 
constexpr int N = 1e6 + 10;
constexpr int inf = 0x3f3f3f3f; 
int n, k, m; 
// int us[N][30], uss[N][30]; 
void solve() {
    cin >> n >> k >> m;
    string s; 
    cin >> s; 
    string ans = ""; 
    int o = 0; 
    for(int i = 0; i < m; i ++ ) {
        set<char> se; 
        se.insert(s[i]); 
        int j = i; 
        while(se.size() < k && j + 1 < m) {
            ++ j; 
            se.insert(s[j]); 
        }
        if(se.size() < k) {
            for(int j = 0; j < k; j ++ )
                if(se.count(('a' + j)) == 0) {
                    ans += ('a' + j); 
                    break; 
                }
        }
        else o ++, ans += s[j]; 
        
        i = j; 
    }
    if(o >= n) cout << "YES" << endl; 
    else {
        cout << "NO" << endl; 
        while(ans.size() < n) ans += 'a'; 
        cout << ans << endl;
    }
}
signed main() {
    ios::sync_with_stdio(false); 
    cin.tie(0); 
    cout.tie(0); 
    int ts; 
    cin >> ts; 
        
    while(ts -- ) solve(); 
    
    return 0;
}

Part5 思维构造题模型和例题

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
Problem - A - Codeforces

相关推荐
唐叔在学习1 分钟前
【唐叔学算法】第19天:交换排序-冒泡排序与快速排序的深度解析及Java实现
java·算法·排序算法
_nirvana_w_1 分钟前
C语言实现常用排序算法
c语言·算法·排序算法
Moweiii5 分钟前
SDL3 GPU编程探索
c++·游戏引擎·图形渲染·sdl·vulkan
唐叔在学习9 分钟前
【唐叔学算法】第18天:解密选择排序的双重魅力-直接选择排序与堆排序的Java实现及性能剖析
数据结构·算法·排序算法
渝妳学C33 分钟前
【C++】类和对象(下)
c++
Kenneth風车41 分钟前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)11
算法·机器学习·分类
最后一个bug1 小时前
rt-linux中使用mlockall与free的差异
linux·c语言·arm开发·单片机·嵌入式硬件·算法
EleganceJiaBao1 小时前
【C语言】结构体模块化编程
c语言·c++·模块化·static·结构体·struct·耦合
xianwu5431 小时前
反向代理模块。开发
linux·开发语言·网络·c++·git
Bucai_不才1 小时前
【C++】初识C++之C语言加入光荣的进化(上)
c语言·c++·面向对象