Educational Codeforces Round 47 G. Allowed Letters

G. Allowed Letters

题意:给一个长度为 n n n的字符串,字符串元素范围为 a a a f f f,有 m m m个限制条件,每个条件限制了某位置只能填指定元素,你要给字符串重新排列,求排列后字典序最小的字符串。
解法:不妨把重排的字符串看成二分图的左边集合,原字符串看成二分图的右边集合,我们来给它们进行字典序最小的二分图最大匹配,我们可以从前往后枚举每个位置填的最小字符,然后用 h a l l hall hall定理去 c h e c k check check,设 c n t [ s ] cnt[s] cnt[s]为原字符串集合为 s s s时包含了多少个元素,设 v a l [ i ] val[i] val[i]为第 i i i个位置能填的字符集合,设 d [ i ] [ s ] d[i][s] d[i][s] i − n i-n in的位置 s s s s s s的子集包含了多少个 v a l [ j ] val[j] val[j],每次我们枚举 i i i位置上填的字符 j j j,当所有的集合 s s s都满足 c n t [ s ] − ( s > > j & 1 ) = d [ i + 1 ] [ s ] cnt[s]-(s>>j\&1)=d[i+1][s] cnt[s](s>>j&1)=d[i+1][s]时才能去填 j j j,那么这题就写完了
#include 
using namespace std;
const int maxn = 1e5 + 10;
char s[maxn];
int cnt[1 << 6], d[maxn][1 << 6], val[maxn];
int main()
{
    int n, m, x;
    scanf("%s", s + 1);
    n = strlen(s + 1);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j < 1 << 6; j++)
            if (j >> (s[i] - 'a') & 1)
                cnt[j]++;
    }
    scanf("%d", &m);
    for (int i = 1; i <= m; i++)
    {
        scanf("%d%s", &x, s + 1);
        for (int j = 1; s[j]; j++)
            val[x] |= 1 << s[j] - 'a';
    }
    for (int i = n; i; i--)
    {
        if (!val[i])
            val[i] = (1 << 6) - 1;
        for (int j = 1; j < 1 << 6; j++)
        {
            d[i][j] = d[i + 1][j];
            if ((j & val[i]) == val[i])
                d[i][j]++;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        int ok = 0;
        for (int j = 0; j < 6; j++)
            if (val[i] >> j & 1)
            {
                int okk = 1;
                for (int k = 1; (k < 1 << 6) && okk; k++)
                    if (cnt[k] - ((k >> j) & 1) < d[i + 1][k])
                        okk = 0;
                if (okk)
                {
                    s[i] = j + 'a';
                    ok = 1;
                    for (int k = 1; k < 1 << 6; k++)
                        if (k >> j & 1)
                            cnt[k]--;
                    break;
                }
            }
        if (!ok)
            return puts("Impossible"), 0;
    }
    s[n + 1] = '\0';
    puts(s + 1);
}

你可能感兴趣的:(codeforces题解)