BZOJ 4560 [JLoi2016]字符串覆盖

贪心+KMP

一副区间DP的样子,然而并不是

如果只有两个串,那我们可以枚举它们的先后顺序。对于maxans则让前一个串在尽量前的位置匹配,后一个串在尽量后的位置匹配。对于minans则枚举前一个串匹配的位置,把后一个串放在第一个串开头后面第一个匹配位置。

推广下去就有了四个串的做法。枚举顺序,对于maxans,第i+1个串的开头要么在第i个串结尾后的第一个匹配位置,要么在第i个串内部的最后一个匹配位置。枚举一下状态即可。对于minans,枚举第2个串的匹配位置,则第一个串一定在第2个串之前的最后面的匹配位置,对于第三个串,要么在第2个串内的最前位置,要么在第2个串后的任意位置。对于后者用后缀Min维护即可。

然后就港了。

#include
#include
#include
#define N 10005
#define cmax(u,v) ((u)<(v)?(u)=(v):0)
#define cmin(u,v) ((u)>(v)?(u)=(v):0)
using namespace std;
namespace runzhe2000
{
    const int INF = 1<<30;
    bool mat[5][N];
    int n, m, len[5], next[5][N], h[5], lef[5][N], rig[5][N], maxans, minans, sufmin[N];
    char str[N], s[5][N];

    void KMP_next(char *s, int len, int *next)
    {
        next[1] = 0; int p = 0;
        for(int i = 2; i <= len; i++)
        {
            for(; s[p+1] != s[i] && p; p = next[p]);
            if(s[p+1] == s[i]) ++p;
            next[i] = p;
        }
    }

    void KMP_solve(char *s, int len, int *next, bool *mat, int *lef, int *rig)
    {
        int p = 0;
        for(int i = 1; i <= n; i++)
        {
            for(; str[i] != s[p+1] && p; p = next[p]);
            if(str[i] == s[p+1]) p++;
            if(p == len)
            {
                p = next[p];
                mat[i-len+1] = 1;
            }
            else mat[i-len+1] = 0;
        }
        for(int i = n-len+2; i <= n+1; i++) mat[i] = 0;
        p = 0; for(int i = 0; i <= n+1; i++) lef[i] = p, mat[i] ? p=i : 0;
        p = 0; for(int i = n+1; i >= 0; i--) rig[i] = p, mat[i] ? p=i : 0;
    }

    void dfs_make(int nnow, int l, int r, int sum)
    {
        if(nnow > m){cmax(maxans, sum); return;}
        int now = h[nnow];
        int nl, nr;
        nl = lef[now][r+1];
        if(nl >= l && nl > 0)
        {
            nr = nl + len[now] - 1;
            dfs_make(nnow+1, nl, max(nr, r), sum + max(0, len[now] - (r-nl+1)));
        }
        nl = rig[now][r];
        if(nl > 0)
        {
            nr = nl + len[now] - 1;
            dfs_make(nnow+1, nl, nr, sum + len[now]);
        }
    }
    void dfs_init(int now)
    {
        if(now > m) {dfs_make(1,0,0,0);return;}
        for(int i = 1; i <= m; i++)
            if(!h[i]) {h[i] = now; dfs_init(now + 1); h[i] = 0;}
    }

    void main()
    {
        int T; scanf("%d",&T);
        for(; T--; )
        {
            maxans = 0; minans = INF;
            memset(h,0,sizeof h);
            scanf("%s%d",str + 1,&m);
            n = strlen(str + 1);
            for(int i = 1; i <= m; i++)
            {
                scanf("%s",s[i] + 1);
                len[i] = strlen(s[i] + 1);
                KMP_next(s[i], len[i], next[i]);
                KMP_solve(s[i], len[i], next[i], mat[i], lef[i], rig[i]);
            }
            dfs_init(1);

            if(m == 1) minans = len[1];
            else if(m == 2)
            {
                for(int i = 1; i <= n; i++)
                    for(int j = 1; j <= 2; j++)
                        if(mat[j][i] && rig[3-j][i-1])
                        {
                            int tmp = len[j] + len[3-j] - max(0, min(i + len[j] - rig[3-j][i-1], len[3-j]));
                            cmin(minans, tmp);
                        }
            }
            else if(m == 3)
            {
                for(int i = 1; i <= 3; i++)
                    for(int j = 1; j <= 3; j++) if(i != j)
                        for(int k = 1; k <= 3; k++) if(j != k && i != k)
                            for(int p = 1; p <= n; p++)
                                if(mat[j][p] && lef[i][p+1] && rig[k][p-1])
                                {
                                    int r = p + len[j] - 1, q = lef[i][p+1], g = rig[k][p-1];
                                    int tmp = len[i] + len[j] - max(0, min(r, q+len[i]-1) - p + 1);
                                    r = max(r, q+len[i] - 1);
                                    tmp = tmp + len[k] - max(0, min(r, g+len[k]-1) - g + 1);
                                    cmin(minans, tmp);
                                }
            }
            else
            {
                for(h[1] = 1; h[1] <= 4; h[1]++)
                    for(h[2] = 1; h[2] <= 4; h[2]++) if(h[1] != h[2])
                        for(h[3] = 1; h[3] <= 4; h[3]++) if(h[1] != h[3] && h[2]!=h[3])
                            for(h[4] = 1; h[4] <= 4; h[4]++) if(h[1] != h[4] && h[2] != h[4] && h[3] != h[4])
                            {
                                int cur = INF;
                                for(int i = n+1; i >= 1; i--)
                                {
                                    if(mat[h[3]][i] && rig[h[4]][i-1])
                                    {
                                        int p = rig[h[4]][i-1];
                                        int tmp = len[h[3]] + len[h[4]] - max(0, min(i+len[h[3]]-1, p+len[h[4]]-1) - p + 1);
                                        cmin(cur, tmp);
                                    }
                                    sufmin[i] = cur;
                                }
                                for(int i = 1; i <= n; i++)
                                    if(mat[h[2]][i] && lef[h[1]][i+1])
                                    {
                                        int p = lef[h[1]][i+1], r = max(i+len[h[2]]-1, p+len[h[1]]-1);
                                        int tmp = len[h[1]] + len[h[2]] - max(0, min(i+len[h[2]]-1, p+len[h[1]]-1) - i + 1);    
                                        int q = rig[h[3]][i-1];
                                        if(q <= r)
                                        {
                                            int ttmp = tmp + len[h[3]] - (min(r, q + len[h[3]] - 1) - q + 1), tr = max(r, q + len[h[3]] - 1);
                                            int g = rig[h[4]][q-1];
                                            if(g)
                                            {
                                                ttmp = ttmp + len[h[4]] - max(0, min(tr, g + len[h[4]] - 1) - g + 1);
                                                cmin(minans, ttmp);
                                            }
                                        }
                                        tmp = tmp + sufmin[r+1];
                                        cmin(minans, tmp);
                                    }
                            }
            }
            printf("%d %d\n",minans, maxans);
        }
    }
}
int main()
{
    runzhe2000::main();
}

你可能感兴趣的:(其它-贪心,字符串-KMP)