CF1009G
本文节选自我的二分图学习笔记,欢迎来玩!
有一个长为
的字符串 ,只包含 共 种字符。你知道每种字符的出现次数,和每个位置可能出现哪些字符,你需要构造出满足条件且字典序最小的 。
不难发现这是一个位置和字符之间的匹配问题,考虑建图网络流。
设字符
然而直接网络流难以找到字典序最小的匹配。网络流算法的流程很复杂,我们把握不住,所以尽量不要尝试改动网络流的板子,而是考虑其他方法。
最大 / 最小化字典序的问题都可以贪心。从前往后枚举位置
注意到如果不算源点和汇点,这就判断二分图是否有完美多重匹配(多重匹配:每个点
此时我们需要引入 Hall 定理:
对于二分图
,定义函数 表示与 中的点有连边的点的数量,则 存在完美匹配的充要条件是 。
我们显然不能枚举位置部的所有子集,但是字符部只有
对于每个
设字符集为
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
// #define int ll
#define gmin(x, y) (x = min(x, y))
#define gmax(x, y) (x = max(x, y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 1e5 + 5;
int n, t, cnt[6], sum[64], f[N][64];
bool ava[N][6];
string s;
signed main() {
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
cin >> s; n = s.size();
for(auto c : s) cnt[c - 'a']++;
rep(i, 0, 63) rep(j, 0, 5) if(i >> j & 1) sum[i] += cnt[j];
cin >> t;
memset(ava, 1, sizeof ava);
rep(i, 1, t) {
int p; cin >> p >> s;
memset(ava[p], 0, sizeof ava[p]);
for(auto c : s) ava[p][c - 'a'] = 1;
}
per(i, n, 1) {
memcpy(f[i], f[i + 1], sizeof f[i]);
rep(j, 0, 63) rep(k, 0, 5)
if((j >> k & 1) && ava[i][k])
{ ++f[i][j]; break; }
}
s.clear();
rep(i, 1, n) {
bool flg = 0;
rep(j, 0, 5) if(ava[i][j]) {
bool fl = 1;
rep(k, 0, 63)
if(k >> j & 1) {
if(f[i + 1][k] < sum[k] - 1) { fl = 0; break; }
}
else if(f[i + 1][k] < sum[k]) { fl = 0; break; }
if(fl) {
flg = 1; s.push_back(j + 'a');
rep(k, 0, 63) if(k >> j & 1) --sum[k];
break;
}
}
if(!flg) cout << "Impossible\n", exit(0);
}
cout << s << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?