• [JZOJ3105]拼图


    题目大意:
       给你一个起始串$a(|a|leq 300)$,一个目标串$b(|b|leq 300)$,以及$n(nleq 8)$个小串$s_0,s_2,ldots,s_{n-1}(|s_i|leq 400)$,你可以进行若干次操作将$a$变成$b$。
      操作的规则如下:
    ​  1.取出每个小串的任一后缀,代价为去除后缀的长度;
      2.移除起始串中的若干字符,每移除一个字符需要$1$的代价。
      3.选择一些小串并将其插入到$a$中(包括左边界,不包括右边界);
      问将$a$变成$b$的最小代价。

    思路:
      状压DP。
      用$f_{i,j}=k$表示选取小串的状态为$i$,目标串匹配长度为$j$时,起始串$a$匹配的最少长度为$k$。
      对于状态$f_{i,j}$转移时分两种情况,一种是用起始串的一个字母匹配,另一种是用小串来匹配。
      用起始串匹配时,找到$a$中下一个和$b_{j+1}$相同的字符$a_k$,向$f_{i,j+1}$转移。
      用小串匹配时,枚举没有选过的小串$s_k$找到能和目标串匹配的最长前缀长度$l$,向$f_{i+2^k,j+l}$转移。
      最后统计答案时,枚举最后小串选取的状态,答案即为起始串长度+选取的小串长度-目标串长度。
      边界情况:$f_{i,j}geq|a|$,这时再转移就到了$a$的右边界,因此不予转移。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<cstring>
     4 #include<algorithm>
     5 inline int getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register int x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 const unsigned inf=~0u;
    13 const int LEN1=302,LEN2=402,N=8;
    14 char s1[LEN1],s2[LEN1],s[N][LEN2];
    15 unsigned f[1<<N][LEN1],len1,len2,len3[N];
    16 int main() {
    17     scanf("%s%s",&s1[1],&s2[1]);
    18     len1=strlen(&s1[1]),len2=strlen(&s2[1]);
    19     const int n=getint();
    20     for(register int i=0;i<n;i++) {
    21         scanf("%s",&s[i][1]);
    22         len3[i]=strlen(&s[i][1]);
    23     }
    24     memset(f,0xff,sizeof f);
    25     f[0][0]=0;
    26     for(register int i=0;i<1<<n;i++) {
    27         for(register int j=0;j<(int)len2;j++) {
    28             if(f[i][j]>=len1) continue;
    29             for(register unsigned k=f[i][j]+1;s1[k];k++) {
    30                 if(s1[k]==s2[j+1]) {
    31                     f[i][j+1]=std::min(f[i][j+1],k);
    32                     break;
    33                 }
    34             }
    35             for(register int k=0;k<n;k++) {
    36                 if(i&(1<<k)) continue;
    37                 for(register int l=1;s[k][l]&&j+l<=(int)len2&&s[k][l]==s2[j+l];l++) {
    38                     f[i|(1<<k)][j+l]=std::min(f[i|(1<<k)][j+l],f[i][j]);
    39                 }
    40             }
    41         }
    42     }
    43     unsigned ans=inf;
    44     for(register int i=0;i<1<<n;i++) {
    45         if(f[i][len2]==inf) continue;
    46         unsigned tmp=0;
    47         for(register int j=0;j<n;j++) {
    48             if(i&(1<<j)) tmp+=len3[j];
    49         }
    50         ans=std::min(ans,len1+tmp-len2);
    51     }
    52     printf("%u
    ",ans);
    53     return 0;
    54 }
  • 相关阅读:
    Codeforces899D Shovel Sale(思路)
    F
    Codeforces909D Colorful Points(缩点)
    LOD
    Instruments
    IO优化
    Unity JobSystem
    Android 设备指纹
    帧同步
    寻路
  • 原文地址:https://www.cnblogs.com/skylee03/p/8241652.html
Copyright © 2020-2023  润新知