【Cf Edu #47 G】Allowed Letters
这个题大概就是每一个位置都有一个能填字符的限制(一个点集),给出已有的$n$个字符,问能填出的最小字典序的字符串。
总体思路是贪心,每一位尽量选最小的字符。
关键在于判断在某位选了一个字符后,接下来的位置能否满足限制。
考虑怎么判断有解,这里有一种网络流的思路:
- 有$6$个点,代表了$a - f$$6$个字符,有源点向这些点连边,流量为该字符的个数。
- 另有$2^{6}$个点,代表了各个点集,这些点向汇点连边,流量为该点集在所有限制中出现的次数。
- 如果某个点在一个点集中,则由该点向该点集连流量为$INF$的边。
易得,当流量满流时,有合法解。
当然,用网络流这个模型虽然很容易理解,但如果每一次检验都跑一边的话效率不行,出题人有一种基于调整法的网络流做法,在已知流网络上进行修改,但是我不是很懂,代码也较长,在此不做累述。
此处所用的做法十分简洁。有以下结论:
- 接下来仅考虑某位置选了某个字符后,判断剩下的一个后缀是否有解。
- 定义$cnt_{i}$表示字符$i$的剩余数量,$num_{s}$表示与集合$s$有交的位置(该位置上限制的字符集与$s$有交)。
- 枚举$2^{6}$个集合,当所有的集合都准合法时才有解。
- 准合法的定义是:$\sum_{i = a}^{f} (其中 i \in s) <= num_{s}$。
显然,如果$|s|=1$,即$s$中只有一个字符,那$s$准合法就是$s$合法(存在合法解)。
这里用于说明$s$是合法的当且仅当所有$s$的子集是合法的,且$s$是准合法的。
由于我们从小到大枚举所有集合,可以保证所有之前已经枚举过的集合已经合法了,即它的子集都合法,故只要判断该集合是否准合法。
关于这个条件的必要性:
- 如果$s$不是准合法的,显然$s$不会是合法的,因为没有足够位置放。
- 如果$s$的某一个子集$s_{i}$不合法,也就是$s_{i}$的有关位置$num_{s_{i}}$不够调计,那在$s$的有关位置$num_{s}$中并不会有更多的供$s_{i}$中的字符放置的位置,那$s$也将是不合法的。
关于这个条件的充分性:
- 如果所有它的子集都合法了,并且$s$准合法,就不会存在某一个集合中的元素占用了过多的公共位置,因为那样会导致另一个子集不合法,即产生矛盾。
这样的话就能在$O(nA2^{A})$解决问题了,其中$A$是字符集大小。
$\bigodot$技巧与套路:
- 利用网络流的模型
- 集合的枚举以及使用
#include <cstdio>
#include <cstring>
#include <algorithm> const int N = , ST = ; int n, m, bit[N], ans[N], cnt[], num[ST + ][N];
char s[N], ssr[]; inline int Check(int x) {
for (int st = ; st <= ST; ++st) {
int cnum = ;
for (int i = ; i < ; ++i) {
if ((st >> i) & ) cnum += cnt[i];
}
if (num[st][n] - num[st][x] < cnum) return ;
}
return ;
} int main() {
scanf("%s%d", s + , &m);
n = strlen(s + );
for (int i = ; i <= n; ++i) {
bit[i] = ST; ans[i] = -;
++cnt[s[i] - 'a'];
}
for (int i = , x; i <= m; ++i) {
scanf("%d%s", &x, ssr);
int le = strlen(ssr), st = ;
for (int j = ; j < le; ++j) {
st |= << (ssr[j] - 'a');
}
bit[x] &= st;
} for (int st = ; st <= ST; ++st) {
for (int i = ; i <= n; ++i) {
num[st][i] = num[st][i - ] + (bool)(bit[i] & st);
}
} for (int i = ; i <= n; ++i) {
for (int j = ; j < ; ++j) {
--cnt[j];
if (((bit[i] >> j) & ) && Check(i)) {
ans[i] = j; break;
}
++cnt[j];
}
if (ans[i] == -) {
puts("Impossible");
return ;
}
}
for (int i = ; i <= n; ++i) {
putchar(ans[i] + 'a');
} return ;
}
【Cf Edu #47 G】Allowed Letters的更多相关文章
- 【Cf Edu #47 F】Dominant Indices(长链剖分)
要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...
- 【cf contest 1119 G】Get Ready for the Battle
题目 你有\(n\)个士兵,需要将他们分成\(m\)组,每组可以为0: 现在这些士兵要去攻打\(m\)个敌人,每个敌人的生命值为\(hp_i\) : 一轮游戏中一组士兵选定一个攻打的敌人,敌人生命值- ...
- B. Lost Number【CF交互题 暴力】
B. Lost Number[CF交互题 暴力] This is an interactive problem. Remember to flush your output while communi ...
- 【CF edu 27 G. Shortest Path Problem?】
time limit per test 3 seconds memory limit per test 512 megabytes input standard input output standa ...
- 3.26-3.31【cf补题+其他】
计蒜客)翻硬币 //暴力匹配 #include<cstdio> #include<cstring> #define CLR(a, b) memset((a), (b), s ...
- 【郑轻邀请赛 G】密室逃脱
[题目链接]:https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=2133 [题意] [题解] 考虑每一个二进制数的最高位->第i位; 肯定是1(这 ...
- 【cf补题记录】Codeforces Round #608 (Div. 2)
比赛传送门 再次改下写博客的格式,以锻炼自己码字能力 A. Suits 题意:有四种材料,第一套西装需要 \(a\).\(d\) 各一件,卖 \(e\) 块:第二套西装需要 \(b\).\(c\).\ ...
- 【CF 549G Happy Line】排序
题目链接:http://codeforces.com/problemset/problem/549/G 题意:给定一个n个元素的整数序列a[], 任意时刻对于任一对相邻元素a[i-1]. a[i],若 ...
- 【CF 675D Tree Construction】BST
题目链接:http://codeforces.com/problemset/problem/675/D 题意:给一个由n个互异整数组成的序列a[],模拟BST的插入过程,依次输出每插入一个元素a[i] ...
随机推荐
- Unity Shader 学习之旅之SurfaceShader
Unity Shader 学习之旅之SurfaceShader unity shader 图形图像 如果大地的每个角落都充满了光明 谁还需要星星,谁还会 在夜里凝望 寻找遥远的安慰——江河 官方文档 ...
- Redis源码阅读(六)集群-故障迁移(下)
Redis源码阅读(六)集群-故障迁移(下) 最近私人的事情比较多,没有抽出时间来整理博客.书接上文,上一篇里总结了Redis故障迁移的几个关键点,以及Redis中故障检测的实现.本篇主要介绍集群检测 ...
- Hyperledger Fabric 中channel配置相关数据结构
channel Configuration Transaction Hyperledger Fabric区块链网络中的配置存储在一个configuration-transaction的集合中,每个ch ...
- python json模块使用详情
python其他知识目录 #json.数据交换用到json文件.json是特殊的字符串.访问网站,返回的就是json 1.json简介: 定义:JSON(JavaScript Object Notat ...
- [译文]c#扩展方法(Extension Method In C#)
原文链接: https://www.codeproject.com/Tips/709310/Extension-Method-In-Csharp 介绍 扩展方法是C# 3.0引入的新特性.扩展方法使你 ...
- 最新Python笔试题2017 涵盖知识面广泛
引言 想找一份Python开发工作吗?那你很可能得证明自己知道如何使用Python.下面这些问题涉及了与Python相关的许多技能,问题的关注点主要是语言本身,不是某个特定的包或模块.每一个问题都可以 ...
- C++ 类 析构函数
一.析构函数的定义 析构函数为成员函数的一种,名字与类名相同,在前面加‘~’没有参数和返回值在C++中“~”是位取反运算符.一个类最多只能有一个析构函数.析构函数不返回任何值,没有函数类型,也没有函数 ...
- C++ 函数 参数传递方式
用函数调用所给出的实参(实际参数,actual arguments)向函数定义给出的形参(形式参数,formal arguments)设置初始值的过程,叫做参数传递(Argument Passing) ...
- MathExam小学一二年级计算题生成器V1.0
MathExam小学一二年级计算题生成器v1.0 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning ...
- iOS应用程序内打开指定qq聊天、给某人打电话
-(void)btn2Clik { UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero]; NSURL *url = [N ...