Allowed Letters Hall定理
阿新 • • 發佈:2018-12-16
題意:
給你一個字串,你可以任意交換字元,現在要求某些下標只能是一個字元集合裡面的字元,問字典序最小是多少?
字元在a - f之間。
題解:
把所有原來的字母當成二分圖左邊部分, 右邊部分是所有下標的字元集合, 如果字元出現在字元集合中就連邊,一種方案就是一種完美匹配。
現在要貪心的求字典序最小,我們只要列舉每個位置選哪個字元,然後用hall定理判斷選之後還是否能構成完美匹配即可。
程式碼:
#include <bits/stdc++.h> #ifdef LOCAL #define debug(x) cout<<#x<<" = "<<(x)<<endl; #else #define debug(x) 1; #endif #define chmax(x,y) x=max(x,y) #define chmin(x,y) x=min(x,y) #define lson id<<1,l,mid #define rson id<<1|1,mid+1,r #define lowbit(x) x&-x #define mp make_pair #define pb push_back #define fir first #define sec second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const int MOD = 1e9 + 7; const double PI = acos (-1.); const double eps = 1e-10; const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3f; const int MAXN = 5e5 + 5; int cnt[MAXN][1 << 6]; char s[MAXN], t[MAXN]; int cnt2[6]; int val[MAXN]; char ans[MAXN]; int main() { #ifdef LOCAL freopen ("input.txt", "r", stdin); #endif int m; scanf ("%s %d", s + 1, &m); int n = strlen (s + 1); for (int i = 1; i <= n; i++) cnt2[s[i] - 'a']++; for (int i = 1; i <= m; i++) { int id; scanf ("%d %s", &id, t); for (int j = 0; t[j]; j++) val[id] |= (1 << (t[j] - 'a') ); } for (int i = n; i >= 1; i--) { if (val[i] == 0) val[i] = (1 << 6) - 1; for (int j = 0; j < (1 << 6); j++) { cnt[i][j] = cnt[i + 1][j]; if (j & val[i]) cnt[i][j]++; } } for (int i = 1; i <= n; i++) { int can = 0; for (int j = 0; j < 6; j++) { if (cnt2[j] && (val[i] >> j & 1)) { cnt2[j]--; int ok = 1; for (int k = 0; k < (1 << 6); k++) { int num1 = 0; for (int l = 0; l < 6; l++) if (k >> l & 1) num1 += cnt2[l]; if (num1 > cnt[i + 1][k]) ok = 0; } if (ok) { ans[i] = j + 'a'; can = 1; break; } cnt2[j]++; } } if (!can) return 0 * puts ("Impossible"); } printf ("%s\n", ans + 1); return 0; }