寒假思维训练计划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

相关推荐
zzz9332 分钟前
transformer实战——mask
算法
INS_KF22 分钟前
【C++知识杂记2】free和delete区别
c++·笔记·学习
一只鱼^_30 分钟前
牛客周赛 Round 105
数据结构·c++·算法·均值算法·逻辑回归·动态规划·启发式算法
是阿建吖!31 分钟前
【动态规划】斐波那契数列模型
算法·动态规划
ikkkkkkkl32 分钟前
C++设计模式:面向对象设计原则
c++·设计模式·面向对象
啊阿狸不会拉杆1 小时前
《算法导论》第 27 章 - 多线程算法
java·jvm·c++·算法·图论
重启的码农1 小时前
ggml介绍 (8) 图分配器 (ggml_gallocr)
c++·人工智能·神经网络
火车叨位去19491 小时前
力扣top100(day04-05)--堆
算法·leetcode·职场和发展
数据智能老司机1 小时前
面向企业的图学习扩展——面向图的传统机器学习
算法·机器学习
重启的码农1 小时前
ggml介绍 (9) 后端调度器 (ggml_backend_sched)
c++·人工智能·神经网络