1 条题解

  • 0
    @ 2025-8-24 21:47:11

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar kczno1
    **

    搬运于2025-08-24 21:47:11,当前版本为作者最后更新于2017-02-18 17:14:16,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    n<=4,n!枚举放置顺序。

    最大值:

    要尽量少交。

    第一个串应该放的尽量前面。

    第二个串开头如果跟第一个串不交,应该放在尽量前面;

    如果跟第一个串交,应该放在尽量后面,因为如果把前两个串看作一个整体,这样会最长。

    后面也一样。

    最小值:

    第一个串如果不选择第一个位置放,就是一个2->l,1->n的子问题。

    如果选择第一个位置放,

    如果第二个串不交第一个串,就是末尾+1->l,2->n的一个子问题。

    否则第二个串应该放的尽量前面,因为如果把前两个串看作一个整体,这样会最短。

    后面的也一样。

    dp,状态数O(nl),转移O(1)。

    #include<bits/stdc++.h>
    using namespace std;
    
    void chmax(int &x,int y) { if(x<y)x=y; }
    void chmin(int &x,int y) { if(x>y)x=y; }
    #define N 5
    #define L 10005
    char s[L];int l;
    char q[1003];int m;
    int pre[N][L],next[N][L],len[N],n;//pre:<=第一个开头匹配 next:>=第一个开头匹配 
    int id[N],*pr[N],*nex[N],le[N];
    int fail[L],i,j;
    void init()
    {
        for (i=2;i<=m;++i)
        {
            char now=q[i];
            j=fail[i-1];
            while (j&&q[j+1]!=now) j=fail[j];
            fail[i]=(q[j+1]==now)?j+1:0;
        }
    }
    
    bool mark[L];
    void ins(int *pre,int *next)
    {
        i=0;
        for (j=1;j<=l;++j)
        {
            char now=s[j];
            while (i&&q[i+1]!=now) i=fail[i];
            if (q[i+1]==now) 
            {
                ++i;
                if (i==m) mark[j-m+1]=1;
            }
        }
        for (i=1;i<=l;++i) pre[i]=mark[i]?i:pre[i-1];
        pre[i]=pre[i-1];
        next[l+1]=0;
        for (i=l;i;--i) 
        if (mark[i]) {next[i]=i;mark[i]=0;}
        else next[i]=next[i+1];
    }
    
    int f[L][N];bool vis[L][N];
    bool *st[N*L];int top;
    int dp(int first,int num)//first:字符串=[first..l] num:第几个子串   
    {
        if (num>n) return 0;
        first=nex[num][first];
        int &ans=f[first][num];
        if (*(st[top+1]=&vis[first][num])) return ans;*st[++top]=1;
        ans=dp(first+1,num); 
        int last=first+le[num],x0=first;//x0是num-1的开头 
        while ((++num)<=n)
        {
            chmin(ans,dp(last,num)+last-first);//第num个选择不交 
            int x=nex[num][first];
            if (x<x0||x>=last) return ans;
            x0=x;
            chmax(last,x+le[num]);//选择交
        }
        chmin(ans,last-first);
        return ans;
    }
    
    int get(int first,int num)
    {
        if (num>n) return 0;
        first=nex[num][first];
        if(!first) return -L;
        int last=first+le[num],x0=first,ans=-L;
        while ((++num)<=n)
        {
          chmax(ans,get(last,num)+last-first); //不交 
          int x=pr[num][last];//交:尽量后面 
          if (x<x0||x>=last) return ans;
          x0=x;
          chmax(last,x+le[num]);
        }
        return max(ans,last-first);
    } 
    
    int main()
    {
        freopen("1.in","r",stdin);freopen("1.out","w",stdout);
        for (i=1;i<=4;++i) { vis[0][i]=1;f[0][i]=L; }
        int tt,i,j;scanf("%d",&tt);
        while (tt--)
        {
            scanf("%s",s+1);l=strlen(s+1);
            scanf("%d",&n);
            for (i=1;i<=n;++i) 
            {
                scanf("%s",q+1);len[i]=m=strlen(q+1);
                init();
                ins(pre[i],next[i]);
            }
            for (i=1;i<=n;++i) id[i]=i;
            int ans1=L,ans2=0;
            do
            {
                for (i=1;i<=n;++i) {pr[i]=pre[id[i]];nex[i]=next[id[i]];le[i]=len[id[i]];}
                chmin(ans1,dp(1,1));
                for (;top;--top) *st[top]=0;
                chmax(ans2,get(1,1));
            }while (next_permutation(id+1,id+n+1));
            printf("%d %d\n",ans1,ans2);
        }
    }
    
    • 1

    信息

    ID
    2342
    时间
    1000ms
    内存
    125MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者